diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..96bbb19f8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +; Top-most http://editorconfig.org/ file +root = true + +[*] +end_of_line = CRLF + +[*.{cs,xaml,xml}] +indent_style = space +indent_size = 4 + +[*.{md,yml}] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..585d15e64 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +-- +### Environment + +- Fluent.Ribbon __v?.?.?__ +- Theme __?__ +- Windows __?__ +- .NET Framework __?.?__ diff --git a/.gitignore b/.gitignore index c5d44cb84..5e1c8efc9 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,10 @@ publish/ *.nupkg # Generated files -Fluent/Themes/**/Generic.xaml -!Fluent/Themes/Generic.xaml +Fluent.Ribbon/Themes/**/Generic.xaml packages/ +.tmp + +# Allowed files +!Fluent.Ribbon/Themes/Generic.xaml +!Fluent.Ribbon/Themes/XamlCombine.exe \ No newline at end of file diff --git a/Build.cmd b/Build.cmd deleted file mode 100644 index 85150330b..000000000 --- a/Build.cmd +++ /dev/null @@ -1,11 +0,0 @@ -@ECHO OFF - -SET MSBuildUseNoSolutionCache=1 -SET msbuildexe="%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" - -%msbuildexe% Fluent.Ribbon.msbuild /target:Build /property:Configuration=Debug /v:m /nologo -%msbuildexe% Fluent.Ribbon.msbuild /target:Build /property:Configuration=Release /v:m /nologo - -IF NOT ERRORLEVEL 0 EXIT /B %ERRORLEVEL% - -pause \ No newline at end of file diff --git a/Build.ps1 b/Build.ps1 new file mode 100644 index 000000000..ae7c58390 --- /dev/null +++ b/Build.ps1 @@ -0,0 +1,21 @@ +Param( + [Parameter(Mandatory=$False)] + [string]$Configuration = "Release", + [Parameter(Mandatory=$False)] + [switch]$Publish, + [Parameter(Mandatory=$False)] + [string]$PreRelease +) + +$ErrorActionPreference = "Stop" + +. $PSScriptRoot\MSBuildHelper.ps1 + +$target = "Build" +if ($Publish) { $target = "PublishVersion" } + +Write-Output Building +$msbuild = Get-MSBuild +&$msbuild Fluent.Ribbon.msbuild /target:$target /property:Configuration=$Configuration /property:Prerelease=$PreRelease /v:m /nologo + +if ($LASTEXITCODE -ne 0) { exit 1 } \ No newline at end of file diff --git a/BuildForPublish.cmd b/BuildForPublish.cmd deleted file mode 100644 index a9ed6c578..000000000 --- a/BuildForPublish.cmd +++ /dev/null @@ -1,21 +0,0 @@ -@ECHO OFF - -SET prerelease= - -IF NOT '%1'=='' ( - :: Build a prerelease package - IF NOT '%1'=='stable' ( - SET prerelease=%1 - ) -) - -SET MSBuildUseNoSolutionCache=1 -SET msbuildexe="%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" - -:: Build for Debug and Release to have a last visible point for potential compile warnings/errors -%msbuildexe% Fluent.Ribbon.msbuild /target:Build /property:Configuration=Debug /property:Prerelease=%prerelease% /v:m /nologo -%msbuildexe% Fluent.Ribbon.msbuild /target:PublishVersion /property:Configuration=Release /property:Prerelease=%prerelease% /v:m /nologo - -IF NOT ERRORLEVEL 0 EXIT /B %ERRORLEVEL% - -pause \ No newline at end of file diff --git a/Changelog.md b/Changelog.md index a224026df..cf950fb3a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,71 @@ # Changelog for Fluent.Ribbon +## 4.0.0 (preview) + +- ### Notices + - **As of now the Office 2010 and Windows 8 themes will be removed in version 5.0. You can vote for this at [Future direction of this library](../../issues/282).** + +- ### Breaking changes + - New nuget dependency: [ControlzEx](https://www.nuget.org/packages/ControlzEx). So don't forget to add ControlzEx.dll to your distribution/setup. + - BorderlessWindowBehavior was replaced by WindowChromeBehavior from [ControlzEx](https://github.com/ControlzEx/ControlzEx). + This also removes the dependency Microsoft.Windows.Shell as ControlzEx contains everything we need to use WindowChrome. + This behavior is initialized in code behind (InitializeWindowChromeBehavior) and shows which properties of RibbonWindow can be used to control the behavior. + - SaveWindowPosition and WindowSettingBehavior were removed [#196](../../issues/196) + - GlassBorderThickness was renamed to GlassFrameThickness to be consitent with WindowChrome and WindowChromeBehavior [#209](../../issues/209) + - FluentTest project was renamed to Fluent.Ribbon.Showcase [#212](../../issues/212) + +- ### Development/Contributing changes + - We switched to Visual Studio 2015 so we can use nameof etc. [#219](../../issues/219) + +- ### Bug fixes + - [#10](../../issues/10) - Maximising a ribbon window with DWM enabled results in it not maximising properly + - [#90](../../issues/90) - Window chrome turning black during window resize. + - [#116](../../issues/116) - MenuItem: When the description is long the MenuItem does not expands in Width or Height, does not wrap text + - [#129](../../issues/129) - DontUseDwm="True" case the window corner unpainted + - [#146](../../issues/146) - Rendering of Office 2010 theme incorrect on Windows 10 + - [#191](../../issues/191) - Windows 8 Theme - Blue/black margin around the window in windows 10 + - [#210](../../issues/210) - Fix wrong dimensions assumed for WindowCaptionButtons on Windows 10 in Office2010 and Windows 8 themes + - [#218](../../issues/218) - Not displaying properly when maximized + - [#221](../../issues/221) - Office2013 theme undesired space between tabItem and its content when showing unpinned + - [#223](../../issues/223) - RibbonContextualTabGroup ignores Window.ResizeMode + - [#226](../../issues/226) - Maximising a ribbon window on Win7 "Non-Aero" Mode causes rendering issues + - [#228](../../issues/228) - Backstage disappears when changing DontUseDwm + - [#234](../../issues/234) - Disable KeyTips when Ribbon isn't Enabled + - [#235](../../issues/235) - Items of invisble tab are shown + - [#236](../../issues/236) - Window size is wrong when window is maximized, backstage is closed and window should be restored to normal size + - [#237](../../issues/237) - Ribbon Buttons with large text cut off a few pixels + - [#238](../../issues/238) - New WindowChrome does not work correctly on Windows 7 + - [#240](../../issues/240) - Backstage closes when popup is dismissed inside backstage + - [#241](../../issues/241) - Keytips should be cancelled if Alt+Num0 is pressed + - [#244](../../issues/244) - KeyTip not working for childs of ContentPresenter + - [#246](../../issues/246) - Bind RibbonGroupBox.DataContext on QuickAccessToolBar (thanks to @nishy2000) + - [#251](../../issues/251) - Changing RibbonStatusBar height to 23 and RibbonStatusBarItem foreground to BackstageFontBrush (thanks to @maurosampietro) + - [#253](../../issues/253) - Icons of buttons not aligned correctly in Office 2013 theme (thanks to @floele-sp) + - [#254](../../issues/254) - Basic fix for KeyTips not working when focus is inside a WinForms control + - [#256](../../issues/256) - ComboBox items don't update properly on ItemsSource binding source collection changes + - [#255](../../issues/255) - Submenus don't show scroll viewer if items exceed the available space on screen (thanks to @floele-sp) + - [#257](../../issues/257) - Windows8 RibbonWindowTitleTextGlowBackground was missing (thanks to @maurosampietro) + - [#263](../../issues/263) - Changing theme from backstage is broken + - [#267](../../issues/267) - maximizing in Win 10 + - [#269](../../issues/269) - Show underscore of header text on RibbonTabItem + - [#272](../../issues/272) - Changing RibbonThemeColorBrush does not change background of ItemsPanel in Backstage + - [#274](../../issues/274) - RadioButton Icon and LargeIcon + - [#280](../../issues/280) - Keytips of the Ribbon overlay StartScreen + - [#284](../../issues/284) - Overriding width of button does not work as it should + - [#285](../../issues/285) - MaterialDesign DialogHost issue with FluentRibbon + - [#291](../../issues/291) - BackStageTabItem leftmousedown event not firing + - OpenBackstage command was not acting on the correct backstage in a multiple backstage scenario (thanks to @maurosampietro) + +- ### Enhancements + - [#120](../../issues/120) - Adding short-cuts or additional information to Application Menu Item + - [#185](../../issues/185) - Major refactoring of how WindowChrome is used + - [#194](../../issues/194) - There should be an option to disable animations in the whole control + - [#205](../../issues/205) - Fluent Spinner handles Format="P0" incorrectly. + - [#207](../../issues/207) - Enable DragMove on unused RibbonTabControl space like in Office 2013 + - [#230](../../issues/230) - Option to disable the "Minimize"-Ribbon Button & Behavior (thanks to @robertmuehsig) + - [#242](../../issues/242) - Add start screen like in office 2013 and upwards + - [#258](../../issues/258) - Refactoring of KeyTipService and KeyTipAdorner (merged with [#264](../../issues/264)) + ## 3.6.1 - ### Bug fixes diff --git a/Dev.NuGet.Config b/Dev.NuGet.Config new file mode 100644 index 000000000..3d6a5a7bf --- /dev/null +++ b/Dev.NuGet.Config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FluentTest/App.xaml b/Fluent.Ribbon.Showcase/App.xaml similarity index 86% rename from FluentTest/App.xaml rename to Fluent.Ribbon.Showcase/App.xaml index 1423f2c40..41983399c 100644 --- a/FluentTest/App.xaml +++ b/Fluent.Ribbon.Showcase/App.xaml @@ -1,14 +1,15 @@ - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/App.xaml.cs b/Fluent.Ribbon.Showcase/App.xaml.cs new file mode 100644 index 000000000..0a00b12ac --- /dev/null +++ b/Fluent.Ribbon.Showcase/App.xaml.cs @@ -0,0 +1,34 @@ +namespace FluentTest +{ + public partial class App + { + public App() + { + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru-RU"); + + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fa"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("hu"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("cs"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("fr"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("pl"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ja"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("nl"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("pt-PT"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("pt-br"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("es"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("zh"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("sv"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("sk"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("uk"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ro"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("it"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ar"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("da"); + //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("az"); + + System.Threading.Thread.CurrentThread.CurrentCulture = System.Threading.Thread.CurrentThread.CurrentUICulture; + } + } +} \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/Commanding/IRelayCommand.cs b/Fluent.Ribbon.Showcase/Commanding/IRelayCommand.cs new file mode 100644 index 000000000..6c3028d0d --- /dev/null +++ b/Fluent.Ribbon.Showcase/Commanding/IRelayCommand.cs @@ -0,0 +1,11 @@ +namespace FluentTest.Commanding +{ + using System; + using System.Windows.Input; + + public interface IRelayCommand : ICommand + { + event EventHandler Executed; + event EventHandler Executing; + } +} \ No newline at end of file diff --git a/FluentTest/Commanding/RelayCommand.cs b/Fluent.Ribbon.Showcase/Commanding/RelayCommand.cs similarity index 87% rename from FluentTest/Commanding/RelayCommand.cs rename to Fluent.Ribbon.Showcase/Commanding/RelayCommand.cs index 8f1779f22..15d1e9794 100644 --- a/FluentTest/Commanding/RelayCommand.cs +++ b/Fluent.Ribbon.Showcase/Commanding/RelayCommand.cs @@ -1,142 +1,133 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Bastian "batzen" Schmidt 2014. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace FluentTest.Commanding -{ - using System; - using System.Diagnostics; - using System.Windows.Input; - - public class RelayCommand : IRelayCommand - { - private readonly Action action; - private readonly Func canExecute; - - protected RelayCommand() - { - } - - public RelayCommand(Action execute) - { - this.action = execute; - } - - public RelayCommand(Action execute, Func canExecute) - : this(execute) - { - this.canExecute = canExecute; - } - - #region IRelayCommand Members - - [DebuggerStepThrough] - public virtual bool CanExecute(object parameter) - { - return this.canExecute == null - || this.canExecute(); - } - - public event EventHandler CanExecuteChanged - { - add { CommandManager.RequerySuggested += value; } - remove { CommandManager.RequerySuggested -= value; } - } - - public event EventHandler Executed; - - public event EventHandler Executing; - - protected void OnExecuted() - { - if (this.Executed != null) - { - this.Executed(this, null); - } - } - - protected void OnExecuting() - { - if (this.Executing != null) - { - this.Executing(this, null); - } - } - - public void Execute(object parameter) - { - this.OnExecuting(); - - this.InvokeAction(parameter); - - this.OnExecuted(); - } - - protected virtual void InvokeAction(object parameter) - { - this.action(); - } - - #endregion // IRelayCommand Members - } - - /// - /// A command whose sole purpose is to - /// relay its functionality to other - /// objects by invoking delegates. The - /// default return value for the CanExecute - /// method is 'true'. - /// - public class RelayCommand : RelayCommand - { - private readonly Action action; - private readonly Func canExecute; - - protected RelayCommand() - { - } - - /// - /// Creates a new command that can always execute. - /// - /// The execution logic. - public RelayCommand(Action action) - : this(action, null) - { - } - - /// - /// Creates a new command. - /// - /// The execution logic. - /// The execution status logic. - public RelayCommand(Action action, Func canExecute) - { - this.action = action; - this.canExecute = canExecute; - } - - /// - /// Defines the method that determines whether the command can execute in its current state. - /// - /// - /// true if this command can be executed; otherwise, false. - /// - /// Data used by the command. If the command does not require data to be passed, this object can be set to null. - public override bool CanExecute(object parameter) - { - return this.canExecute == null - || this.canExecute((T)parameter); - } - - protected override void InvokeAction(object parameter) - { - this.action((T)parameter); - } - } +namespace FluentTest.Commanding +{ + using System; + using System.Diagnostics; + using System.Windows.Input; + + public class RelayCommand : IRelayCommand + { + private readonly Action action; + private readonly Func canExecute; + + protected RelayCommand() + { + } + + public RelayCommand(Action execute) + { + this.action = execute; + } + + public RelayCommand(Action execute, Func canExecute) + : this(execute) + { + this.canExecute = canExecute; + } + + #region IRelayCommand Members + + [DebuggerStepThrough] + public virtual bool CanExecute(object parameter) + { + return this.canExecute == null + || this.canExecute(); + } + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public event EventHandler Executed; + + public event EventHandler Executing; + + protected void OnExecuted() + { + if (this.Executed != null) + { + this.Executed(this, null); + } + } + + protected void OnExecuting() + { + if (this.Executing != null) + { + this.Executing(this, null); + } + } + + public void Execute(object parameter) + { + this.OnExecuting(); + + this.InvokeAction(parameter); + + this.OnExecuted(); + } + + protected virtual void InvokeAction(object parameter) + { + this.action(); + } + + #endregion // IRelayCommand Members + } + + /// + /// A command whose sole purpose is to + /// relay its functionality to other + /// objects by invoking delegates. The + /// default return value for the CanExecute + /// method is 'true'. + /// + public class RelayCommand : RelayCommand + { + private readonly Action action; + private readonly Func canExecute; + + protected RelayCommand() + { + } + + /// + /// Creates a new command that can always execute. + /// + /// The execution logic. + public RelayCommand(Action action) + : this(action, null) + { + } + + /// + /// Creates a new command. + /// + /// The execution logic. + /// The execution status logic. + public RelayCommand(Action action, Func canExecute) + { + this.action = action; + this.canExecute = canExecute; + } + + /// + /// Defines the method that determines whether the command can execute in its current state. + /// + /// + /// true if this command can be executed; otherwise, false. + /// + /// Data used by the command. If the command does not require data to be passed, this object can be set to null. + public override bool CanExecute(object parameter) + { + return this.canExecute == null + || this.canExecute((T)parameter); + } + + protected override void InvokeAction(object parameter) + { + this.action((T)parameter); + } + } } \ No newline at end of file diff --git a/FluentTest/FluentTest dotNET 4.0.csproj b/Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.0.csproj similarity index 92% rename from FluentTest/FluentTest dotNET 4.0.csproj rename to Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.0.csproj index 78f716221..430d4ddc9 100644 --- a/FluentTest/FluentTest dotNET 4.0.csproj +++ b/Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.0.csproj @@ -1,246 +1,252 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {2A893D50-BBC4-4482-ADAA-D52B517E8632} - WinExe - Properties - FluentTest - FluentTest - v4.0 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - Icons\App.ico - ..\build\obj\NET 4.0 - $(BaseIntermediateOutputPath)\$(Configuration)\ - - - true - full - false - ..\build\bin\NET 4.0\Debug\ - DEBUG;TRACE - prompt - 4 - false - AllRules.ruleset - - - pdbonly - true - ..\build\bin\NET 4.0\Release\ - TRACE - prompt - 4 - AllRules.ruleset - false - - - - ..\packages\MahApps.Metro.1.0.0.0\lib\net40\MahApps.Metro.dll - - - - - - ..\packages\MahApps.Metro.1.0.0.0\lib\net40\System.Windows.Interactivity.dll - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - Properties\GlobalAssemblyInfo.cs - - - - - MahMetroWindow.xaml - - - - RegularWindow.xaml - - - RibbonWindowWithoutVisibileRibbon.xaml - - - TestContent.xaml - - - - - - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - TestWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - {4C92FCF4-3561-499F-BC5B-F2F089863046} - Fluent dotNET 4.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2A893D50-BBC4-4482-ADAA-D52B517E8632} + WinExe + Properties + FluentTest + Fluent.Ribbon.Showcase + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + Icons\App.ico + ..\build\obj\NET 4.0 + $(BaseIntermediateOutputPath)\$(Configuration)\ + + + true + full + false + ..\build\bin\NET 4.0\Debug\ + DEBUG;TRACE + prompt + 4 + false + AllRules.ruleset + + + pdbonly + true + ..\build\bin\NET 4.0\Release\ + TRACE + prompt + 4 + AllRules.ruleset + false + + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net40\MahApps.Metro.dll + True + + + + + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net40\System.Windows.Interactivity.dll + True + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + Properties\GlobalAssemblyInfo.cs + + + + + MahMetroWindow.xaml + + + + RegularWindow.xaml + + + RibbonWindowWithoutVisibileRibbon.xaml + + + + + TestContent.xaml + + + + + + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + TestWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {281095D8-D8B3-4A7F-8896-646483FB685C} + Fluent.Ribbon.NET 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FluentTest/FluentTest dotNET 4.5.csproj b/Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.5.csproj similarity index 93% rename from FluentTest/FluentTest dotNET 4.5.csproj rename to Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.5.csproj index dd0882188..8fe8f3594 100644 --- a/FluentTest/FluentTest dotNET 4.5.csproj +++ b/Fluent.Ribbon.Showcase/Fluent.Ribbon.Showcase.NET 4.5.csproj @@ -1,253 +1,259 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {2C2A076B-E626-4A07-9D6E-4AEE3FEC41B6} - WinExe - Properties - FluentTest - FluentTest - v4.5 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - Icons\App.ico - ..\build\obj\NET 4.5 - true - 4.0.20408.0 - $(BaseIntermediateOutputPath)\$(Configuration)\ - - - true - full - false - ..\build\bin\NET 4.5\Debug\ - DEBUG;TRACE - prompt - 4 - false - AllRules.ruleset - false - - - pdbonly - true - ..\build\bin\NET 4.5\Release\ - TRACE - prompt - 4 - AllRules.ruleset - false - false - - - app.manifest - - - - ..\packages\MahApps.Metro.1.0.0.0\lib\net45\MahApps.Metro.dll - - - - - - ..\packages\MahApps.Metro.1.0.0.0\lib\net45\System.Windows.Interactivity.dll - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - Properties\GlobalAssemblyInfo.cs - - - - - MahMetroWindow.xaml - - - - RegularWindow.xaml - - - RibbonWindowWithoutVisibileRibbon.xaml - - - TestContent.xaml - - - - - - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - TestWindow.xaml - Code - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - {4C92FCF4-3561-499F-BC5B-F2F089863047} - Fluent dotNET 4.5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {2C2A076B-E626-4A07-9D6E-4AEE3FEC41B6} + WinExe + Properties + FluentTest + Fluent.Ribbon.Showcase + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + Icons\App.ico + ..\build\obj\NET 4.5 + true + 4.0.20408.0 + $(BaseIntermediateOutputPath)\$(Configuration)\ + + + true + full + false + ..\build\bin\NET 4.5\Debug\ + DEBUG;TRACE + prompt + 4 + false + AllRules.ruleset + false + + + pdbonly + true + ..\build\bin\NET 4.5\Release\ + TRACE + prompt + 4 + AllRules.ruleset + false + false + + + app.manifest + + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net45\MahApps.Metro.dll + True + + + + + + + ..\packages\MahApps.Metro.1.1.2.0\lib\net45\System.Windows.Interactivity.dll + True + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + Properties\GlobalAssemblyInfo.cs + + + + + MahMetroWindow.xaml + + + + RegularWindow.xaml + + + RibbonWindowWithoutVisibileRibbon.xaml + + + + + TestContent.xaml + + + + + + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + TestWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + {4C92FCF4-3561-499F-BC5B-F2F089863047} + Fluent.Ribbon.NET 4.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/Helpers/TemplateCollection.cs b/Fluent.Ribbon.Showcase/Helpers/TemplateCollection.cs new file mode 100644 index 000000000..b3505b5d0 --- /dev/null +++ b/Fluent.Ribbon.Showcase/Helpers/TemplateCollection.cs @@ -0,0 +1,10 @@ +namespace FluentTest.Helpers +{ + using System.Collections.Generic; + using System.Windows; + + /// Holds a collection of items for application as a control's DataTemplate. + public class TemplateCollection : List + { + } +} diff --git a/FluentTest/Icons/App.ico b/Fluent.Ribbon.Showcase/Icons/App.ico similarity index 100% rename from FluentTest/Icons/App.ico rename to Fluent.Ribbon.Showcase/Icons/App.ico diff --git a/FluentTest/Images/BlackTheme.png b/Fluent.Ribbon.Showcase/Images/BlackTheme.png similarity index 100% rename from FluentTest/Images/BlackTheme.png rename to Fluent.Ribbon.Showcase/Images/BlackTheme.png diff --git a/FluentTest/Images/Blue.png b/Fluent.Ribbon.Showcase/Images/Blue.png similarity index 100% rename from FluentTest/Images/Blue.png rename to Fluent.Ribbon.Showcase/Images/Blue.png diff --git a/FluentTest/Images/BlueLarge.png b/Fluent.Ribbon.Showcase/Images/BlueLarge.png similarity index 100% rename from FluentTest/Images/BlueLarge.png rename to Fluent.Ribbon.Showcase/Images/BlueLarge.png diff --git a/FluentTest/Images/BlueTheme.png b/Fluent.Ribbon.Showcase/Images/BlueTheme.png similarity index 100% rename from FluentTest/Images/BlueTheme.png rename to Fluent.Ribbon.Showcase/Images/BlueTheme.png diff --git a/FluentTest/Images/Bold.png b/Fluent.Ribbon.Showcase/Images/Bold.png similarity index 100% rename from FluentTest/Images/Bold.png rename to Fluent.Ribbon.Showcase/Images/Bold.png diff --git a/FluentTest/Images/Box.png b/Fluent.Ribbon.Showcase/Images/Box.png similarity index 100% rename from FluentTest/Images/Box.png rename to Fluent.Ribbon.Showcase/Images/Box.png diff --git a/FluentTest/Images/Brown.png b/Fluent.Ribbon.Showcase/Images/Brown.png similarity index 100% rename from FluentTest/Images/Brown.png rename to Fluent.Ribbon.Showcase/Images/Brown.png diff --git a/FluentTest/Images/BrownLarge.png b/Fluent.Ribbon.Showcase/Images/BrownLarge.png similarity index 100% rename from FluentTest/Images/BrownLarge.png rename to Fluent.Ribbon.Showcase/Images/BrownLarge.png diff --git a/FluentTest/Images/ChangeCase.png b/Fluent.Ribbon.Showcase/Images/ChangeCase.png similarity index 100% rename from FluentTest/Images/ChangeCase.png rename to Fluent.Ribbon.Showcase/Images/ChangeCase.png diff --git a/FluentTest/Images/ClearFormatting.png b/Fluent.Ribbon.Showcase/Images/ClearFormatting.png similarity index 100% rename from FluentTest/Images/ClearFormatting.png rename to Fluent.Ribbon.Showcase/Images/ClearFormatting.png diff --git a/FluentTest/Images/Copy.png b/Fluent.Ribbon.Showcase/Images/Copy.png similarity index 100% rename from FluentTest/Images/Copy.png rename to Fluent.Ribbon.Showcase/Images/Copy.png diff --git a/FluentTest/Images/Cut.png b/Fluent.Ribbon.Showcase/Images/Cut.png similarity index 100% rename from FluentTest/Images/Cut.png rename to Fluent.Ribbon.Showcase/Images/Cut.png diff --git a/FluentTest/Images/Default.png b/Fluent.Ribbon.Showcase/Images/Default.png similarity index 100% rename from FluentTest/Images/Default.png rename to Fluent.Ribbon.Showcase/Images/Default.png diff --git a/FluentTest/Images/Exit.png b/Fluent.Ribbon.Showcase/Images/Exit.png similarity index 100% rename from FluentTest/Images/Exit.png rename to Fluent.Ribbon.Showcase/Images/Exit.png diff --git a/FluentTest/Images/FontColor.png b/Fluent.Ribbon.Showcase/Images/FontColor.png similarity index 100% rename from FluentTest/Images/FontColor.png rename to Fluent.Ribbon.Showcase/Images/FontColor.png diff --git a/FluentTest/Images/FormatPainter.png b/Fluent.Ribbon.Showcase/Images/FormatPainter.png similarity index 100% rename from FluentTest/Images/FormatPainter.png rename to Fluent.Ribbon.Showcase/Images/FormatPainter.png diff --git a/FluentTest/Images/GalleryLarge.png b/Fluent.Ribbon.Showcase/Images/GalleryLarge.png similarity index 100% rename from FluentTest/Images/GalleryLarge.png rename to Fluent.Ribbon.Showcase/Images/GalleryLarge.png diff --git a/FluentTest/Images/Gray.png b/Fluent.Ribbon.Showcase/Images/Gray.png similarity index 100% rename from FluentTest/Images/Gray.png rename to Fluent.Ribbon.Showcase/Images/Gray.png diff --git a/FluentTest/Images/GrayLarge.png b/Fluent.Ribbon.Showcase/Images/GrayLarge.png similarity index 100% rename from FluentTest/Images/GrayLarge.png rename to Fluent.Ribbon.Showcase/Images/GrayLarge.png diff --git a/FluentTest/Images/Green.png b/Fluent.Ribbon.Showcase/Images/Green.png similarity index 100% rename from FluentTest/Images/Green.png rename to Fluent.Ribbon.Showcase/Images/Green.png diff --git a/FluentTest/Images/GreenLarge.png b/Fluent.Ribbon.Showcase/Images/GreenLarge.png similarity index 100% rename from FluentTest/Images/GreenLarge.png rename to Fluent.Ribbon.Showcase/Images/GreenLarge.png diff --git a/FluentTest/Images/GrowFont.png b/Fluent.Ribbon.Showcase/Images/GrowFont.png similarity index 100% rename from FluentTest/Images/GrowFont.png rename to Fluent.Ribbon.Showcase/Images/GrowFont.png diff --git a/FluentTest/Images/Help.png b/Fluent.Ribbon.Showcase/Images/Help.png similarity index 100% rename from FluentTest/Images/Help.png rename to Fluent.Ribbon.Showcase/Images/Help.png diff --git a/FluentTest/Images/Italic.png b/Fluent.Ribbon.Showcase/Images/Italic.png similarity index 100% rename from FluentTest/Images/Italic.png rename to Fluent.Ribbon.Showcase/Images/Italic.png diff --git a/FluentTest/Images/Orange.png b/Fluent.Ribbon.Showcase/Images/Orange.png similarity index 100% rename from FluentTest/Images/Orange.png rename to Fluent.Ribbon.Showcase/Images/Orange.png diff --git a/FluentTest/Images/OrangeLarge.png b/Fluent.Ribbon.Showcase/Images/OrangeLarge.png similarity index 100% rename from FluentTest/Images/OrangeLarge.png rename to Fluent.Ribbon.Showcase/Images/OrangeLarge.png diff --git a/FluentTest/Images/Paste.png b/Fluent.Ribbon.Showcase/Images/Paste.png similarity index 100% rename from FluentTest/Images/Paste.png rename to Fluent.Ribbon.Showcase/Images/Paste.png diff --git a/FluentTest/Images/PasteFormating.png b/Fluent.Ribbon.Showcase/Images/PasteFormating.png similarity index 100% rename from FluentTest/Images/PasteFormating.png rename to Fluent.Ribbon.Showcase/Images/PasteFormating.png diff --git a/FluentTest/Images/PasteImage.png b/Fluent.Ribbon.Showcase/Images/PasteImage.png similarity index 100% rename from FluentTest/Images/PasteImage.png rename to Fluent.Ribbon.Showcase/Images/PasteImage.png diff --git a/FluentTest/Images/PasteLarge.png b/Fluent.Ribbon.Showcase/Images/PasteLarge.png similarity index 100% rename from FluentTest/Images/PasteLarge.png rename to Fluent.Ribbon.Showcase/Images/PasteLarge.png diff --git a/FluentTest/Images/PasteSourceFormating.png b/Fluent.Ribbon.Showcase/Images/PasteSourceFormating.png similarity index 100% rename from FluentTest/Images/PasteSourceFormating.png rename to Fluent.Ribbon.Showcase/Images/PasteSourceFormating.png diff --git a/FluentTest/Images/PasteText.png b/Fluent.Ribbon.Showcase/Images/PasteText.png similarity index 100% rename from FluentTest/Images/PasteText.png rename to Fluent.Ribbon.Showcase/Images/PasteText.png diff --git a/FluentTest/Images/PasteTextOnly.png b/Fluent.Ribbon.Showcase/Images/PasteTextOnly.png similarity index 100% rename from FluentTest/Images/PasteTextOnly.png rename to Fluent.Ribbon.Showcase/Images/PasteTextOnly.png diff --git a/FluentTest/Images/Pink.png b/Fluent.Ribbon.Showcase/Images/Pink.png similarity index 100% rename from FluentTest/Images/Pink.png rename to Fluent.Ribbon.Showcase/Images/Pink.png diff --git a/FluentTest/Images/PinkLarge.png b/Fluent.Ribbon.Showcase/Images/PinkLarge.png similarity index 100% rename from FluentTest/Images/PinkLarge.png rename to Fluent.Ribbon.Showcase/Images/PinkLarge.png diff --git a/FluentTest/Images/Red.png b/Fluent.Ribbon.Showcase/Images/Red.png similarity index 100% rename from FluentTest/Images/Red.png rename to Fluent.Ribbon.Showcase/Images/Red.png diff --git a/FluentTest/Images/RedLarge.png b/Fluent.Ribbon.Showcase/Images/RedLarge.png similarity index 100% rename from FluentTest/Images/RedLarge.png rename to Fluent.Ribbon.Showcase/Images/RedLarge.png diff --git a/FluentTest/Images/SampleImageForScreenTip.png b/Fluent.Ribbon.Showcase/Images/SampleImageForScreenTip.png similarity index 100% rename from FluentTest/Images/SampleImageForScreenTip.png rename to Fluent.Ribbon.Showcase/Images/SampleImageForScreenTip.png diff --git a/FluentTest/Images/Save.png b/Fluent.Ribbon.Showcase/Images/Save.png similarity index 100% rename from FluentTest/Images/Save.png rename to Fluent.Ribbon.Showcase/Images/Save.png diff --git a/FluentTest/Images/ShrinkFont.png b/Fluent.Ribbon.Showcase/Images/ShrinkFont.png similarity index 100% rename from FluentTest/Images/ShrinkFont.png rename to Fluent.Ribbon.Showcase/Images/ShrinkFont.png diff --git a/FluentTest/Images/SilverTheme.png b/Fluent.Ribbon.Showcase/Images/SilverTheme.png similarity index 100% rename from FluentTest/Images/SilverTheme.png rename to Fluent.Ribbon.Showcase/Images/SilverTheme.png diff --git a/FluentTest/Images/Strikethrough.png b/Fluent.Ribbon.Showcase/Images/Strikethrough.png similarity index 100% rename from FluentTest/Images/Strikethrough.png rename to Fluent.Ribbon.Showcase/Images/Strikethrough.png diff --git a/FluentTest/Images/Subscript.png b/Fluent.Ribbon.Showcase/Images/Subscript.png similarity index 100% rename from FluentTest/Images/Subscript.png rename to Fluent.Ribbon.Showcase/Images/Subscript.png diff --git a/FluentTest/Images/Superscript.png b/Fluent.Ribbon.Showcase/Images/Superscript.png similarity index 100% rename from FluentTest/Images/Superscript.png rename to Fluent.Ribbon.Showcase/Images/Superscript.png diff --git a/FluentTest/Images/Test16.png b/Fluent.Ribbon.Showcase/Images/Test16.png similarity index 100% rename from FluentTest/Images/Test16.png rename to Fluent.Ribbon.Showcase/Images/Test16.png diff --git a/FluentTest/Images/Test32.png b/Fluent.Ribbon.Showcase/Images/Test32.png similarity index 100% rename from FluentTest/Images/Test32.png rename to Fluent.Ribbon.Showcase/Images/Test32.png diff --git a/FluentTest/Images/TextEffects.png b/Fluent.Ribbon.Showcase/Images/TextEffects.png similarity index 100% rename from FluentTest/Images/TextEffects.png rename to Fluent.Ribbon.Showcase/Images/TextEffects.png diff --git a/FluentTest/Images/TextHighlightColor.png b/Fluent.Ribbon.Showcase/Images/TextHighlightColor.png similarity index 100% rename from FluentTest/Images/TextHighlightColor.png rename to Fluent.Ribbon.Showcase/Images/TextHighlightColor.png diff --git a/FluentTest/Images/Underline.png b/Fluent.Ribbon.Showcase/Images/Underline.png similarity index 100% rename from FluentTest/Images/Underline.png rename to Fluent.Ribbon.Showcase/Images/Underline.png diff --git a/FluentTest/Images/VectorIcons.xaml b/Fluent.Ribbon.Showcase/Images/VectorIcons.xaml similarity index 100% rename from FluentTest/Images/VectorIcons.xaml rename to Fluent.Ribbon.Showcase/Images/VectorIcons.xaml diff --git a/FluentTest/Images/Yellow.png b/Fluent.Ribbon.Showcase/Images/Yellow.png similarity index 100% rename from FluentTest/Images/Yellow.png rename to Fluent.Ribbon.Showcase/Images/Yellow.png diff --git a/FluentTest/Images/YellowLarge.png b/Fluent.Ribbon.Showcase/Images/YellowLarge.png similarity index 100% rename from FluentTest/Images/YellowLarge.png rename to Fluent.Ribbon.Showcase/Images/YellowLarge.png diff --git a/FluentTest/MahMetroWindow.xaml b/Fluent.Ribbon.Showcase/MahMetroWindow.xaml similarity index 100% rename from FluentTest/MahMetroWindow.xaml rename to Fluent.Ribbon.Showcase/MahMetroWindow.xaml diff --git a/FluentTest/MahMetroWindow.xaml.cs b/Fluent.Ribbon.Showcase/MahMetroWindow.xaml.cs similarity index 100% rename from FluentTest/MahMetroWindow.xaml.cs rename to Fluent.Ribbon.Showcase/MahMetroWindow.xaml.cs diff --git a/FluentTest/Properties/Annotations.cs b/Fluent.Ribbon.Showcase/Properties/Annotations.cs similarity index 97% rename from FluentTest/Properties/Annotations.cs rename to Fluent.Ribbon.Showcase/Properties/Annotations.cs index 658180ec6..72afa8991 100644 --- a/FluentTest/Properties/Annotations.cs +++ b/Fluent.Ribbon.Showcase/Properties/Annotations.cs @@ -1,624 +1,624 @@ -using System; - -#pragma warning disable 1591 -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedParameter.Local -// ReSharper disable MemberCanBePrivate.Global -// ReSharper disable UnusedAutoPropertyAccessor.Global -// ReSharper disable IntroduceOptionalParameters.Global -// ReSharper disable MemberCanBeProtected.Global -// ReSharper disable InconsistentNaming - -namespace JetBrains.Annotations -{ - /// - /// Indicates that the value of the marked element could be null sometimes, - /// so the check for null is necessary before its usage - /// - /// - /// [CanBeNull] public object Test() { return null; } - /// public void UseTest() { - /// var p = Test(); - /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class CanBeNullAttribute : Attribute { } - - /// - /// Indicates that the value of the marked element could never be null - /// - /// - /// [NotNull] public object Foo() { - /// return null; // Warning: Possible 'null' assignment - /// } - /// - [AttributeUsage( - AttributeTargets.Method | AttributeTargets.Parameter | - AttributeTargets.Property | AttributeTargets.Delegate | - AttributeTargets.Field, AllowMultiple = false, Inherited = true)] - public sealed class NotNullAttribute : Attribute { } - - /// - /// Indicates that the marked method builds string by format pattern and (optional) arguments. - /// Parameter, which contains format string, should be given in constructor. The format string - /// should be in -like form - /// - /// - /// [StringFormatMethod("message")] - /// public void ShowError(string message, params object[] args) { /* do something */ } - /// public void Foo() { - /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string - /// } - /// - [AttributeUsage( - AttributeTargets.Constructor | AttributeTargets.Method, - AllowMultiple = false, Inherited = true)] - public sealed class StringFormatMethodAttribute : Attribute - { - /// - /// Specifies which parameter of an annotated method should be treated as format-string - /// - public StringFormatMethodAttribute(string formatParameterName) - { - this.FormatParameterName = formatParameterName; - } - - public string FormatParameterName { get; private set; } - } - - /// - /// Indicates that the function argument should be string literal and match one - /// of the parameters of the caller function. For example, ReSharper annotates - /// the parameter of - /// - /// - /// public void Foo(string param) { - /// if (param == null) - /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol - /// } - /// - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] - public sealed class InvokerParameterNameAttribute : Attribute { } - - /// - /// Indicates that the method is contained in a type that implements - /// interface - /// and this method is used to notify that some property value changed - /// - /// - /// The method should be non-static and conform to one of the supported signatures: - /// - /// NotifyChanged(string) - /// NotifyChanged(params string[]) - /// NotifyChanged{T}(Expression{Func{T}}) - /// NotifyChanged{T,U}(Expression{Func{T,U}}) - /// SetProperty{T}(ref T, T, string) - /// - /// - /// - /// public class Foo : INotifyPropertyChanged { - /// public event PropertyChangedEventHandler PropertyChanged; - /// [NotifyPropertyChangedInvocator] - /// protected virtual void NotifyChanged(string propertyName) { ... } - /// - /// private string _name; - /// public string Name { - /// get { return _name; } - /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } - /// } - /// } - /// - /// Examples of generated notifications: - /// - /// NotifyChanged("Property") - /// NotifyChanged(() => Property) - /// NotifyChanged((VM x) => x.Property) - /// SetProperty(ref myField, value, "Property") - /// - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] - public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute - { - public NotifyPropertyChangedInvocatorAttribute() { } - public NotifyPropertyChangedInvocatorAttribute(string parameterName) - { - this.ParameterName = parameterName; - } - - public string ParameterName { get; private set; } - } - - /// - /// Describes dependency between method input and output - /// - /// - ///

Function Definition Table syntax:

- /// - /// FDT ::= FDTRow [;FDTRow]* - /// FDTRow ::= Input => Output | Output <= Input - /// Input ::= ParameterName: Value [, Input]* - /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} - /// Value ::= true | false | null | notnull | canbenull - /// - /// If method has single input parameter, it's name could be omitted.
- /// Using halt (or void/nothing, which is the same) - /// for method output means that the methos doesn't return normally.
- /// canbenull annotation is only applicable for output parameters.
- /// You can use multiple [ContractAnnotation] for each FDT row, - /// or use single attribute with rows separated by semicolon.
- ///
- /// - /// - /// [ContractAnnotation("=> halt")] - /// public void TerminationMethod() - /// - /// - /// [ContractAnnotation("halt <= condition: false")] - /// public void Assert(bool condition, string text) // regular assertion method - /// - /// - /// [ContractAnnotation("s:null => true")] - /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() - /// - /// - /// // A method that returns null if the parameter is null, and not null if the parameter is not null - /// [ContractAnnotation("null => null; notnull => notnull")] - /// public object Transform(object data) - /// - /// - /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] - /// public bool TryParse(string s, out Person result) - /// - /// - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] - public sealed class ContractAnnotationAttribute : Attribute - { - public ContractAnnotationAttribute([NotNull] string contract) - : this(contract, false) { } - - public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) - { - this.Contract = contract; - this.ForceFullStates = forceFullStates; - } - - public string Contract { get; private set; } - public bool ForceFullStates { get; private set; } - } - - /// - /// Indicates that marked element should be localized or not - /// - /// - /// [LocalizationRequiredAttribute(true)] - /// public class Foo { - /// private string str = "my string"; // Warning: Localizable string - /// } - /// - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] - public sealed class LocalizationRequiredAttribute : Attribute - { - public LocalizationRequiredAttribute() : this(true) { } - public LocalizationRequiredAttribute(bool required) - { - this.Required = required; - } - - public bool Required { get; private set; } - } - - /// - /// Indicates that the value of the marked type (or its derivatives) - /// cannot be compared using '==' or '!=' operators and Equals() - /// should be used instead. However, using '==' or '!=' for comparison - /// with null is always permitted. - /// - /// - /// [CannotApplyEqualityOperator] - /// class NoEquality { } - /// class UsesNoEquality { - /// public void Test() { - /// var ca1 = new NoEquality(); - /// var ca2 = new NoEquality(); - /// if (ca1 != null) { // OK - /// bool condition = ca1 == ca2; // Warning - /// } - /// } - /// } - /// - [AttributeUsage( - AttributeTargets.Interface | AttributeTargets.Class | - AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] - public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } - - /// - /// When applied to a target attribute, specifies a requirement for any type marked - /// with the target attribute to implement or inherit specific type or types. - /// - /// - /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement - /// public class ComponentAttribute : Attribute { } - /// [Component] // ComponentAttribute requires implementing IComponent interface - /// public class MyComponent : IComponent { } - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] - [BaseTypeRequired(typeof(Attribute))] - public sealed class BaseTypeRequiredAttribute : Attribute - { - public BaseTypeRequiredAttribute([NotNull] Type baseType) - { - this.BaseType = baseType; - } - - [NotNull] - public Type BaseType { get; private set; } - } - - /// - /// Indicates that the marked symbol is used implicitly - /// (e.g. via reflection, in external library), so this symbol - /// will not be marked as unused (as well as by other usage inspections) - /// - [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] - public sealed class UsedImplicitlyAttribute : Attribute - { - public UsedImplicitlyAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - public UsedImplicitlyAttribute( - ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) - { - this.UseKindFlags = useKindFlags; - this.TargetFlags = targetFlags; - } - - public ImplicitUseKindFlags UseKindFlags { get; private set; } - public ImplicitUseTargetFlags TargetFlags { get; private set; } - } - - /// - /// Should be used on attributes and causes ReSharper - /// to not mark symbols marked with such attributes as unused - /// (as well as by other usage inspections) - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] - public sealed class MeansImplicitUseAttribute : Attribute - { - public MeansImplicitUseAttribute() - : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) - : this(useKindFlags, ImplicitUseTargetFlags.Default) { } - - public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) - : this(ImplicitUseKindFlags.Default, targetFlags) { } - - public MeansImplicitUseAttribute( - ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) - { - this.UseKindFlags = useKindFlags; - this.TargetFlags = targetFlags; - } - - [UsedImplicitly] - public ImplicitUseKindFlags UseKindFlags { get; private set; } - [UsedImplicitly] - public ImplicitUseTargetFlags TargetFlags { get; private set; } - } - - [Flags] - public enum ImplicitUseKindFlags - { - Default = Access | Assign | InstantiatedWithFixedConstructorSignature, - /// Only entity marked with attribute considered used - Access = 1, - /// Indicates implicit assignment to a member - Assign = 2, - /// - /// Indicates implicit instantiation of a type with fixed constructor signature. - /// That means any unused constructor parameters won't be reported as such. - /// - InstantiatedWithFixedConstructorSignature = 4, - /// Indicates implicit instantiation of a type - InstantiatedNoFixedConstructorSignature = 8, - } - - /// - /// Specify what is considered used implicitly - /// when marked with - /// or - /// - [Flags] - public enum ImplicitUseTargetFlags - { - Default = Itself, - Itself = 1, - /// Members of entity marked with attribute are considered used - Members = 2, - /// Entity marked with attribute and all its members considered used - WithMembers = Itself | Members - } - - /// - /// This attribute is intended to mark publicly available API - /// which should not be removed and so is treated as used - /// - [MeansImplicitUse] - public sealed class PublicAPIAttribute : Attribute - { - public PublicAPIAttribute() { } - public PublicAPIAttribute([NotNull] string comment) - { - this.Comment = comment; - } - - [NotNull] - public string Comment { get; private set; } - } - - /// - /// Tells code analysis engine if the parameter is completely handled - /// when the invoked method is on stack. If the parameter is a delegate, - /// indicates that delegate is executed while the method is executed. - /// If the parameter is an enumerable, indicates that it is enumerated - /// while the method is executed - /// - [AttributeUsage(AttributeTargets.Parameter, Inherited = true)] - public sealed class InstantHandleAttribute : Attribute { } - - /// - /// Indicates that a method does not make any observable state changes. - /// The same as System.Diagnostics.Contracts.PureAttribute - /// - /// - /// [Pure] private int Multiply(int x, int y) { return x * y; } - /// public void Foo() { - /// const int a = 2, b = 2; - /// Multiply(a, b); // Waring: Return value of pure method is not used - /// } - /// - [AttributeUsage(AttributeTargets.Method, Inherited = true)] - public sealed class PureAttribute : Attribute { } - - /// - /// Indicates that a parameter is a path to a file or a folder - /// within a web project. Path can be relative or absolute, - /// starting from web root (~) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public class PathReferenceAttribute : Attribute - { - public PathReferenceAttribute() { } - public PathReferenceAttribute([PathReference] string basePath) - { - this.BasePath = basePath; - } - - [NotNull] - public string BasePath { get; private set; } - } - - // ASP.NET MVC attributes - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute - { - public AspMvcAreaMasterLocationFormatAttribute(string format) { } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute - { - public AspMvcAreaPartialViewLocationFormatAttribute(string format) { } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute - { - public AspMvcAreaViewLocationFormatAttribute(string format) { } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcMasterLocationFormatAttribute : Attribute - { - public AspMvcMasterLocationFormatAttribute(string format) { } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute - { - public AspMvcPartialViewLocationFormatAttribute(string format) { } - } - - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class AspMvcViewLocationFormatAttribute : Attribute - { - public AspMvcViewLocationFormatAttribute(string format) { } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC action. If applied to a method, the MVC action name is calculated - /// implicitly from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcActionAttribute : Attribute - { - public AspMvcActionAttribute() { } - public AspMvcActionAttribute([NotNull] string anonymousProperty) - { - this.AnonymousProperty = anonymousProperty; - } - - [NotNull] - public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcAreaAttribute : PathReferenceAttribute - { - public AspMvcAreaAttribute() { } - public AspMvcAreaAttribute([NotNull] string anonymousProperty) - { - this.AnonymousProperty = anonymousProperty; - } - - [NotNull] - public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that - /// the parameter is an MVC controller. If applied to a method, - /// the MVC controller name is calculated implicitly from the context. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcControllerAttribute : Attribute - { - public AspMvcControllerAttribute() { } - public AspMvcControllerAttribute([NotNull] string anonymousProperty) - { - this.AnonymousProperty = anonymousProperty; - } - - [NotNull] - public string AnonymousProperty { get; private set; } - } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(String, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcMasterAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(String, Object) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcModelTypeAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that - /// the parameter is an MVC partial view. If applied to a method, - /// the MVC partial view name is calculated implicitly from the context. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { } - - /// - /// ASP.NET MVC attribute. Allows disabling all inspections - /// for MVC views within a class or a method. - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public sealed class AspMvcSupressViewErrorAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcDisplayTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. - /// Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcEditorTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. - /// Use this attribute for custom wrappers similar to - /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String) - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class AspMvcTemplateAttribute : Attribute { } - - /// - /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter - /// is an MVC view. If applied to a method, the MVC view name is calculated implicitly - /// from the context. Use this attribute for custom wrappers similar to - /// System.Web.Mvc.Controller.View(Object) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] - public sealed class AspMvcViewAttribute : PathReferenceAttribute { } - - /// - /// ASP.NET MVC attribute. When applied to a parameter of an attribute, - /// indicates that this parameter is an MVC action name - /// - /// - /// [ActionName("Foo")] - /// public ActionResult Login(string returnUrl) { - /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK - /// return RedirectToAction("Bar"); // Error: Cannot resolve action - /// } - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] - public sealed class AspMvcActionSelectorAttribute : Attribute { } - - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Property | - AttributeTargets.Field, Inherited = true)] - public sealed class HtmlElementAttributesAttribute : Attribute - { - public HtmlElementAttributesAttribute() { } - public HtmlElementAttributesAttribute([NotNull] string name) - { - this.Name = name; - } - - [NotNull] - public string Name { get; private set; } - } - - [AttributeUsage( - AttributeTargets.Parameter | AttributeTargets.Field | - AttributeTargets.Property, Inherited = true)] - public sealed class HtmlAttributeValueAttribute : Attribute - { - public HtmlAttributeValueAttribute([NotNull] string name) - { - this.Name = name; - } - - [NotNull] - public string Name { get; private set; } - } - - // Razor attributes - - /// - /// Razor attribute. Indicates that a parameter or a method is a Razor section. - /// Use this attribute for custom wrappers similar to - /// System.Web.WebPages.WebPageBase.RenderSection(String) - /// - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)] - public sealed class RazorSectionAttribute : Attribute { } +using System; + +#pragma warning disable 1591 +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedParameter.Local +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable IntroduceOptionalParameters.Global +// ReSharper disable MemberCanBeProtected.Global +// ReSharper disable InconsistentNaming + +namespace JetBrains.Annotations +{ + /// + /// Indicates that the value of the marked element could be null sometimes, + /// so the check for null is necessary before its usage + /// + /// + /// [CanBeNull] public object Test() { return null; } + /// public void UseTest() { + /// var p = Test(); + /// var s = p.ToString(); // Warning: Possible 'System.NullReferenceException' + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class CanBeNullAttribute : Attribute { } + + /// + /// Indicates that the value of the marked element could never be null + /// + /// + /// [NotNull] public object Foo() { + /// return null; // Warning: Possible 'null' assignment + /// } + /// + [AttributeUsage( + AttributeTargets.Method | AttributeTargets.Parameter | + AttributeTargets.Property | AttributeTargets.Delegate | + AttributeTargets.Field, AllowMultiple = false, Inherited = true)] + public sealed class NotNullAttribute : Attribute { } + + /// + /// Indicates that the marked method builds string by format pattern and (optional) arguments. + /// Parameter, which contains format string, should be given in constructor. The format string + /// should be in -like form + /// + /// + /// [StringFormatMethod("message")] + /// public void ShowError(string message, params object[] args) { /* do something */ } + /// public void Foo() { + /// ShowError("Failed: {0}"); // Warning: Non-existing argument in format string + /// } + /// + [AttributeUsage( + AttributeTargets.Constructor | AttributeTargets.Method, + AllowMultiple = false, Inherited = true)] + public sealed class StringFormatMethodAttribute : Attribute + { + /// + /// Specifies which parameter of an annotated method should be treated as format-string + /// + public StringFormatMethodAttribute(string formatParameterName) + { + this.FormatParameterName = formatParameterName; + } + + public string FormatParameterName { get; private set; } + } + + /// + /// Indicates that the function argument should be string literal and match one + /// of the parameters of the caller function. For example, ReSharper annotates + /// the parameter of + /// + /// + /// public void Foo(string param) { + /// if (param == null) + /// throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol + /// } + /// + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + public sealed class InvokerParameterNameAttribute : Attribute { } + + /// + /// Indicates that the method is contained in a type that implements + /// interface + /// and this method is used to notify that some property value changed + /// + /// + /// The method should be non-static and conform to one of the supported signatures: + /// + /// NotifyChanged(string) + /// NotifyChanged(params string[]) + /// NotifyChanged{T}(Expression{Func{T}}) + /// NotifyChanged{T,U}(Expression{Func{T,U}}) + /// SetProperty{T}(ref T, T, string) + /// + /// + /// + /// public class Foo : INotifyPropertyChanged { + /// public event PropertyChangedEventHandler PropertyChanged; + /// [NotifyPropertyChangedInvocator] + /// protected virtual void NotifyChanged(string propertyName) { ... } + /// + /// private string _name; + /// public string Name { + /// get { return _name; } + /// set { _name = value; NotifyChanged("LastName"); /* Warning */ } + /// } + /// } + /// + /// Examples of generated notifications: + /// + /// NotifyChanged("Property") + /// NotifyChanged(() => Property) + /// NotifyChanged((VM x) => x.Property) + /// SetProperty(ref myField, value, "Property") + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute + { + public NotifyPropertyChangedInvocatorAttribute() { } + public NotifyPropertyChangedInvocatorAttribute(string parameterName) + { + this.ParameterName = parameterName; + } + + public string ParameterName { get; private set; } + } + + /// + /// Describes dependency between method input and output + /// + /// + ///

Function Definition Table syntax:

+ /// + /// FDT ::= FDTRow [;FDTRow]* + /// FDTRow ::= Input => Output | Output <= Input + /// Input ::= ParameterName: Value [, Input]* + /// Output ::= [ParameterName: Value]* {halt|stop|void|nothing|Value} + /// Value ::= true | false | null | notnull | canbenull + /// + /// If method has single input parameter, it's name could be omitted.
+ /// Using halt (or void/nothing, which is the same) + /// for method output means that the methos doesn't return normally.
+ /// canbenull annotation is only applicable for output parameters.
+ /// You can use multiple [ContractAnnotation] for each FDT row, + /// or use single attribute with rows separated by semicolon.
+ ///
+ /// + /// + /// [ContractAnnotation("=> halt")] + /// public void TerminationMethod() + /// + /// + /// [ContractAnnotation("halt <= condition: false")] + /// public void Assert(bool condition, string text) // regular assertion method + /// + /// + /// [ContractAnnotation("s:null => true")] + /// public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty() + /// + /// + /// // A method that returns null if the parameter is null, and not null if the parameter is not null + /// [ContractAnnotation("null => null; notnull => notnull")] + /// public object Transform(object data) + /// + /// + /// [ContractAnnotation("s:null=>false; =>true,result:notnull; =>false, result:null")] + /// public bool TryParse(string s, out Person result) + /// + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public sealed class ContractAnnotationAttribute : Attribute + { + public ContractAnnotationAttribute([NotNull] string contract) + : this(contract, false) { } + + public ContractAnnotationAttribute([NotNull] string contract, bool forceFullStates) + { + this.Contract = contract; + this.ForceFullStates = forceFullStates; + } + + public string Contract { get; private set; } + public bool ForceFullStates { get; private set; } + } + + /// + /// Indicates that marked element should be localized or not + /// + /// + /// [LocalizationRequiredAttribute(true)] + /// public class Foo { + /// private string str = "my string"; // Warning: Localizable string + /// } + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class LocalizationRequiredAttribute : Attribute + { + public LocalizationRequiredAttribute() : this(true) { } + public LocalizationRequiredAttribute(bool required) + { + this.Required = required; + } + + public bool Required { get; private set; } + } + + /// + /// Indicates that the value of the marked type (or its derivatives) + /// cannot be compared using '==' or '!=' operators and Equals() + /// should be used instead. However, using '==' or '!=' for comparison + /// with null is always permitted. + /// + /// + /// [CannotApplyEqualityOperator] + /// class NoEquality { } + /// class UsesNoEquality { + /// public void Test() { + /// var ca1 = new NoEquality(); + /// var ca2 = new NoEquality(); + /// if (ca1 != null) { // OK + /// bool condition = ca1 == ca2; // Warning + /// } + /// } + /// } + /// + [AttributeUsage( + AttributeTargets.Interface | AttributeTargets.Class | + AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] + public sealed class CannotApplyEqualityOperatorAttribute : Attribute { } + + /// + /// When applied to a target attribute, specifies a requirement for any type marked + /// with the target attribute to implement or inherit specific type or types. + /// + /// + /// [BaseTypeRequired(typeof(IComponent)] // Specify requirement + /// public class ComponentAttribute : Attribute { } + /// [Component] // ComponentAttribute requires implementing IComponent interface + /// public class MyComponent : IComponent { } + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + [BaseTypeRequired(typeof(Attribute))] + public sealed class BaseTypeRequiredAttribute : Attribute + { + public BaseTypeRequiredAttribute([NotNull] Type baseType) + { + this.BaseType = baseType; + } + + [NotNull] + public Type BaseType { get; private set; } + } + + /// + /// Indicates that the marked symbol is used implicitly + /// (e.g. via reflection, in external library), so this symbol + /// will not be marked as unused (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] + public sealed class UsedImplicitlyAttribute : Attribute + { + public UsedImplicitlyAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public UsedImplicitlyAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + this.UseKindFlags = useKindFlags; + this.TargetFlags = targetFlags; + } + + public ImplicitUseKindFlags UseKindFlags { get; private set; } + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + /// + /// Should be used on attributes and causes ReSharper + /// to not mark symbols marked with such attributes as unused + /// (as well as by other usage inspections) + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public sealed class MeansImplicitUseAttribute : Attribute + { + public MeansImplicitUseAttribute() + : this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags) + : this(useKindFlags, ImplicitUseTargetFlags.Default) { } + + public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags) + : this(ImplicitUseKindFlags.Default, targetFlags) { } + + public MeansImplicitUseAttribute( + ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags) + { + this.UseKindFlags = useKindFlags; + this.TargetFlags = targetFlags; + } + + [UsedImplicitly] + public ImplicitUseKindFlags UseKindFlags { get; private set; } + [UsedImplicitly] + public ImplicitUseTargetFlags TargetFlags { get; private set; } + } + + [Flags] + public enum ImplicitUseKindFlags + { + Default = Access | Assign | InstantiatedWithFixedConstructorSignature, + /// Only entity marked with attribute considered used + Access = 1, + /// Indicates implicit assignment to a member + Assign = 2, + /// + /// Indicates implicit instantiation of a type with fixed constructor signature. + /// That means any unused constructor parameters won't be reported as such. + /// + InstantiatedWithFixedConstructorSignature = 4, + /// Indicates implicit instantiation of a type + InstantiatedNoFixedConstructorSignature = 8, + } + + /// + /// Specify what is considered used implicitly + /// when marked with + /// or + /// + [Flags] + public enum ImplicitUseTargetFlags + { + Default = Itself, + Itself = 1, + /// Members of entity marked with attribute are considered used + Members = 2, + /// Entity marked with attribute and all its members considered used + WithMembers = Itself | Members + } + + /// + /// This attribute is intended to mark publicly available API + /// which should not be removed and so is treated as used + /// + [MeansImplicitUse] + public sealed class PublicAPIAttribute : Attribute + { + public PublicAPIAttribute() { } + public PublicAPIAttribute([NotNull] string comment) + { + this.Comment = comment; + } + + [NotNull] + public string Comment { get; private set; } + } + + /// + /// Tells code analysis engine if the parameter is completely handled + /// when the invoked method is on stack. If the parameter is a delegate, + /// indicates that delegate is executed while the method is executed. + /// If the parameter is an enumerable, indicates that it is enumerated + /// while the method is executed + /// + [AttributeUsage(AttributeTargets.Parameter, Inherited = true)] + public sealed class InstantHandleAttribute : Attribute { } + + /// + /// Indicates that a method does not make any observable state changes. + /// The same as System.Diagnostics.Contracts.PureAttribute + /// + /// + /// [Pure] private int Multiply(int x, int y) { return x * y; } + /// public void Foo() { + /// const int a = 2, b = 2; + /// Multiply(a, b); // Waring: Return value of pure method is not used + /// } + /// + [AttributeUsage(AttributeTargets.Method, Inherited = true)] + public sealed class PureAttribute : Attribute { } + + /// + /// Indicates that a parameter is a path to a file or a folder + /// within a web project. Path can be relative or absolute, + /// starting from web root (~) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class PathReferenceAttribute : Attribute + { + public PathReferenceAttribute() { } + public PathReferenceAttribute([PathReference] string basePath) + { + this.BasePath = basePath; + } + + [NotNull] + public string BasePath { get; private set; } + } + + // ASP.NET MVC attributes + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaMasterLocationFormatAttribute : Attribute + { + public AspMvcAreaMasterLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaPartialViewLocationFormatAttribute : Attribute + { + public AspMvcAreaPartialViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcAreaViewLocationFormatAttribute : Attribute + { + public AspMvcAreaViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcMasterLocationFormatAttribute : Attribute + { + public AspMvcMasterLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcPartialViewLocationFormatAttribute : Attribute + { + public AspMvcPartialViewLocationFormatAttribute(string format) { } + } + + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class AspMvcViewLocationFormatAttribute : Attribute + { + public AspMvcViewLocationFormatAttribute(string format) { } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC action. If applied to a method, the MVC action name is calculated + /// implicitly from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcActionAttribute : Attribute + { + public AspMvcActionAttribute() { } + public AspMvcActionAttribute([NotNull] string anonymousProperty) + { + this.AnonymousProperty = anonymousProperty; + } + + [NotNull] + public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC area. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcAreaAttribute : PathReferenceAttribute + { + public AspMvcAreaAttribute() { } + public AspMvcAreaAttribute([NotNull] string anonymousProperty) + { + this.AnonymousProperty = anonymousProperty; + } + + [NotNull] + public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC controller. If applied to a method, + /// the MVC controller name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.ChildActionExtensions.RenderAction(HtmlHelper, String, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcControllerAttribute : Attribute + { + public AspMvcControllerAttribute() { } + public AspMvcControllerAttribute([NotNull] string anonymousProperty) + { + this.AnonymousProperty = anonymousProperty; + } + + [NotNull] + public string AnonymousProperty { get; private set; } + } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC Master. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcMasterAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC model type. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(String, Object) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcModelTypeAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that + /// the parameter is an MVC partial view. If applied to a method, + /// the MVC partial view name is calculated implicitly from the context. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcPartialViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. Allows disabling all inspections + /// for MVC views within a class or a method. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + public sealed class AspMvcSupressViewErrorAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC display template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.DisplayExtensions.DisplayForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcDisplayTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC editor template. + /// Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Html.EditorExtensions.EditorForModel(HtmlHelper, String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcEditorTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. Indicates that a parameter is an MVC template. + /// Use this attribute for custom wrappers similar to + /// System.ComponentModel.DataAnnotations.UIHintAttribute(System.String) + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class AspMvcTemplateAttribute : Attribute { } + + /// + /// ASP.NET MVC attribute. If applied to a parameter, indicates that the parameter + /// is an MVC view. If applied to a method, the MVC view name is calculated implicitly + /// from the context. Use this attribute for custom wrappers similar to + /// System.Web.Mvc.Controller.View(Object) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method)] + public sealed class AspMvcViewAttribute : PathReferenceAttribute { } + + /// + /// ASP.NET MVC attribute. When applied to a parameter of an attribute, + /// indicates that this parameter is an MVC action name + /// + /// + /// [ActionName("Foo")] + /// public ActionResult Login(string returnUrl) { + /// ViewBag.ReturnUrl = Url.Action("Foo"); // OK + /// return RedirectToAction("Bar"); // Error: Cannot resolve action + /// } + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)] + public sealed class AspMvcActionSelectorAttribute : Attribute { } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Property | + AttributeTargets.Field, Inherited = true)] + public sealed class HtmlElementAttributesAttribute : Attribute + { + public HtmlElementAttributesAttribute() { } + public HtmlElementAttributesAttribute([NotNull] string name) + { + this.Name = name; + } + + [NotNull] + public string Name { get; private set; } + } + + [AttributeUsage( + AttributeTargets.Parameter | AttributeTargets.Field | + AttributeTargets.Property, Inherited = true)] + public sealed class HtmlAttributeValueAttribute : Attribute + { + public HtmlAttributeValueAttribute([NotNull] string name) + { + this.Name = name; + } + + [NotNull] + public string Name { get; private set; } + } + + // Razor attributes + + /// + /// Razor attribute. Indicates that a parameter or a method is a Razor section. + /// Use this attribute for custom wrappers similar to + /// System.Web.WebPages.WebPageBase.RenderSection(String) + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Method, Inherited = true)] + public sealed class RazorSectionAttribute : Attribute { } } \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/Properties/AssemblyInfo.cs b/Fluent.Ribbon.Showcase/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..272f22549 --- /dev/null +++ b/Fluent.Ribbon.Showcase/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +[assembly: AssemblyTitle("Fluent.Ribbon.Showcase")] +[assembly: AssemblyDescription("Showcase application for Fluent.Ribbon")] \ No newline at end of file diff --git a/FluentTest/Properties/Resources.Designer.cs b/Fluent.Ribbon.Showcase/Properties/Resources.Designer.cs similarity index 96% rename from FluentTest/Properties/Resources.Designer.cs rename to Fluent.Ribbon.Showcase/Properties/Resources.Designer.cs index f207a2aa6..946f9eef8 100644 --- a/FluentTest/Properties/Resources.Designer.cs +++ b/Fluent.Ribbon.Showcase/Properties/Resources.Designer.cs @@ -1,63 +1,63 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34014 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FluentTest.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FluentTest.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FluentTest.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FluentTest.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/FluentTest/Properties/Resources.resx b/Fluent.Ribbon.Showcase/Properties/Resources.resx similarity index 97% rename from FluentTest/Properties/Resources.resx rename to Fluent.Ribbon.Showcase/Properties/Resources.resx index ffecec851..af7dbebba 100644 --- a/FluentTest/Properties/Resources.resx +++ b/Fluent.Ribbon.Showcase/Properties/Resources.resx @@ -1,117 +1,117 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + \ No newline at end of file diff --git a/FluentTest/Properties/Settings.Designer.cs b/Fluent.Ribbon.Showcase/Properties/Settings.Designer.cs similarity index 91% rename from FluentTest/Properties/Settings.Designer.cs rename to Fluent.Ribbon.Showcase/Properties/Settings.Designer.cs index 54795eddb..4f9fad2bf 100644 --- a/FluentTest/Properties/Settings.Designer.cs +++ b/Fluent.Ribbon.Showcase/Properties/Settings.Designer.cs @@ -1,26 +1,26 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.34014 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FluentTest.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FluentTest.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/FluentTest/Properties/Settings.settings b/Fluent.Ribbon.Showcase/Properties/Settings.settings similarity index 97% rename from FluentTest/Properties/Settings.settings rename to Fluent.Ribbon.Showcase/Properties/Settings.settings index 8f2fd95d6..033d7a5e9 100644 --- a/FluentTest/Properties/Settings.settings +++ b/Fluent.Ribbon.Showcase/Properties/Settings.settings @@ -1,7 +1,7 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/FluentTest/RegularWindow.xaml b/Fluent.Ribbon.Showcase/RegularWindow.xaml similarity index 100% rename from FluentTest/RegularWindow.xaml rename to Fluent.Ribbon.Showcase/RegularWindow.xaml diff --git a/FluentTest/RegularWindow.xaml.cs b/Fluent.Ribbon.Showcase/RegularWindow.xaml.cs similarity index 100% rename from FluentTest/RegularWindow.xaml.cs rename to Fluent.Ribbon.Showcase/RegularWindow.xaml.cs diff --git a/FluentTest/RibbonWindowWithoutVisibileRibbon.xaml b/Fluent.Ribbon.Showcase/RibbonWindowWithoutVisibileRibbon.xaml similarity index 100% rename from FluentTest/RibbonWindowWithoutVisibileRibbon.xaml rename to Fluent.Ribbon.Showcase/RibbonWindowWithoutVisibileRibbon.xaml diff --git a/FluentTest/RibbonWindowWithoutVisibileRibbon.xaml.cs b/Fluent.Ribbon.Showcase/RibbonWindowWithoutVisibileRibbon.xaml.cs similarity index 100% rename from FluentTest/RibbonWindowWithoutVisibileRibbon.xaml.cs rename to Fluent.Ribbon.Showcase/RibbonWindowWithoutVisibileRibbon.xaml.cs diff --git a/Fluent.Ribbon.Showcase/TemplateSelectors/DynamicTemplateSelector.cs b/Fluent.Ribbon.Showcase/TemplateSelectors/DynamicTemplateSelector.cs new file mode 100644 index 000000000..83ea79b71 --- /dev/null +++ b/Fluent.Ribbon.Showcase/TemplateSelectors/DynamicTemplateSelector.cs @@ -0,0 +1,77 @@ +namespace FluentTest.TemplateSelectors +{ + using System; + using System.ComponentModel; + using System.Windows; + using System.Windows.Controls; + using Helpers; + + /// + /// Provides a means to specify DataTemplates to be selected from within WPF code + /// + public class DynamicTemplateSelector : DataTemplateSelector + { + /// Generic attached property specifying s used by the + /// + /// This attached property will allow you to set the templates you wish to be available whenever + /// a control's TemplateSelector is set to an instance of + /// + public static readonly DependencyProperty TemplatesCollectionProperty = + DependencyProperty.RegisterAttached("TemplatesCollection", typeof(TemplateCollection), + typeof(DynamicTemplateSelector), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior)); + + /// Gets the value of the 's attached + /// The who's attached template's property you wish to retrieve + /// The templates used by the givem when using the + [AttachedPropertyBrowsableForType(typeof(ContentControl))] + public static TemplateCollection GetTemplatesCollection(DependencyObject target) + { + return (TemplateCollection)target.GetValue(TemplatesCollectionProperty); + } + + /// Sets the value of the 's attached + /// The element to set the property on + /// The collection of s to apply to this element + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public static void SetTemplatesCollection(DependencyObject target, TemplateCollection value) + { + target.SetValue(TemplatesCollectionProperty, value); + } + + /// + /// Overriden base method to allow the selection of the correct DataTemplate + /// + /// The item for which the template should be retrieved + /// The object containing the current item + /// The to use when rendering the + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + //This should ensure that the item we are getting is in fact capable of holding our property + //before we attempt to retrieve it. + if (container != null) + { + var templates = GetTemplatesCollection(container); + + if (templates != null + && templates.Count != 0) + { + foreach (var template in templates) + { + //In this case, we are checking whether the type of the item + //is the same as the type supported by our DataTemplate + if (template.DataType is Type + && ((Type)template.DataType).IsInstanceOfType(item)) + { + //And if it is, then we return that DataTemplate + return template; + } + } + } + } + + //If all else fails, then we go back to using the default DataTemplate + return new DataTemplate(); + } + } +} \ No newline at end of file diff --git a/FluentTest/TestContent.xaml b/Fluent.Ribbon.Showcase/TestContent.xaml similarity index 88% rename from FluentTest/TestContent.xaml rename to Fluent.Ribbon.Showcase/TestContent.xaml index 72c802832..fc8af6fe8 100644 --- a/FluentTest/TestContent.xaml +++ b/Fluent.Ribbon.Showcase/TestContent.xaml @@ -1,2776 +1,2894 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - - - 1 - 2 - 3 - 4 - 5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This is long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long text - - 123 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Silver - Black - Blue - Don't use DWM - - - - White - - - - White (Experimental) - - - - - Use backstage - - - Use application menu - - - - - - SaveWindowPosition - - - IsIconVisible - - - IsStatusBarVisible - - - - - - ShowQuickAccessToolBarAboveRibbon - - - CanCustomizeQuickAccessToolBar - - - CanCustomizeQuickAccessToolBarItems - - - CanCustomizeRibbon - - - IsMinimized - - - IsCollapsed - - - IsAutomaticCollapseEnabled - - - IsQuickAccessToolBarVisible - - - CanQuickAccessLocationChanging - - - AutomaticStateManagement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Show All - Read-only - Writeable - - - - - - - - - - - - 1 - 2 - 3 - 4 - 5 - 6 - 1 (G 2) - 2 (G 2) - 3 (G 2) - - - - AAAA - First - AAAA - AAAA - AAAA - AAAA - BBBB - BBBB - BBBB - BBBB - BBBB - CCCC - CCCC - CCCC - CCCC - CCCC - DDDD - DDDD - DDDD - DDDD - DDDD - EEEE - EEEE - EEEE - EEEE - EEEE - FFFF - FFFF - FFFF - FFFF - FFFF - GGGG - GGGG - GGGG - GGGG - GGGG - HHHH - HHHH - HHHH - HHHH - HHHH - IIII - IIII - IIII - IIII - IIII - JJJJ - JJJJ - JJJJ - JJJJ - JJJJ - KKKK - KKKK - KKKK - KKKK - KKKK - LLLL - LLLL - LLLL - LLLL - LLLL - MMMM - MMMM - MMMM - MMMM - MMMM - NNNN - NNNN - NNNN - NNNN - NNNN - OOOO - OOOO - OOOO - OOOO - OOOO - PPPP - PPPP - PPPP - PPPP - PPPP - QQQQ - QQQQ - QQQQ - QQQQ - QQQQ - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - AAAA - YYYY - YYYY - YYYY - YYYY - YYYY - ZZZZ - ZZZZ - ZZZZ - ZZZZ - ZZZZ - Last - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Text 1 - Text 2 - Text 3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Test - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - - - - - - - - - 1 - - - 2 - - - 3 - - - 4 - - - 5 - - - 6 - - - 7 - - - 8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Fluent Ribbon Control Suite - - Fluent Ribbon Control Suite is a library that implements an Office-like (Microsoft® Office Fluent™ user interface) for the Windows Presentation Foundation (WPF). - - It provides well-customized controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. - - It is bundled with the most up-to-date Office 2010 and Office 2013 styles. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + You can close the start screen by either clicking the button below or by pressing ESC + Close start screen + + + + + + + + + + + + + + + + + + + + + + + + + + + + Office 2010 Silver + Office 2010 Black + Office 2010 Blue + Office 2013 White + Windows8 White + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + + + 1 + 2 + 3 + 4 + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This is long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long text + + 123 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Silver + Black + Blue + Don't use DWM + + + + White + + + + White + + + + + Use backstage + + + Use application menu + + + Show start screen + + + + + + IsIconVisible + + + IsStatusBarVisible + + + + + + ShowQuickAccessToolBarAboveRibbon + + + CanCustomizeQuickAccessToolBar + + + CanCustomizeQuickAccessToolBarItems + + + CanCustomizeRibbon + + + IsMinimized + + + CanMinimize + + + IsCollapsed + + + IsAutomaticCollapseEnabled + + + IsQuickAccessToolBarVisible + + + CanQuickAccessLocationChanging + + + AutomaticStateManagement + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Show All + Read-only + Writeable + + + + + + + + + + + + 1 + 2 + 3 + 4 + 5 + 6 + 1 (G 2) + 2 (G 2) + 3 (G 2) + + + + AAAA - First + AAAA + AAAA + AAAA + AAAA + BBBB + BBBB + BBBB + BBBB + BBBB + CCCC + CCCC + CCCC + CCCC + CCCC + DDDD + DDDD + DDDD + DDDD + DDDD + EEEE + EEEE + EEEE + EEEE + EEEE + FFFF + FFFF + FFFF + FFFF + FFFF + GGGG + GGGG + GGGG + GGGG + GGGG + HHHH + HHHH + HHHH + HHHH + HHHH + IIII + IIII + IIII + IIII + IIII + JJJJ + JJJJ + JJJJ + JJJJ + JJJJ + KKKK + KKKK + KKKK + KKKK + KKKK + LLLL + LLLL + LLLL + LLLL + LLLL + MMMM + MMMM + MMMM + MMMM + MMMM + NNNN + NNNN + NNNN + NNNN + NNNN + OOOO + OOOO + OOOO + OOOO + OOOO + PPPP + PPPP + PPPP + PPPP + PPPP + QQQQ + QQQQ + QQQQ + QQQQ + QQQQ + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + AAAA + YYYY + YYYY + YYYY + YYYY + YYYY + ZZZZ + ZZZZ + ZZZZ + ZZZZ + ZZZZ + Last + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Text 1 + Text 2 + Text 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + + + + + + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fluent.Ribbon + + Fluent.Ribbon is a library that implements an Office-like user interface for the Windows Presentation Foundation (WPF). + + It provides controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. + + It is bundled with Office 2010, Office 2013 and Windows 8 themes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Test System.Windows.Controls.TextBox + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FluentTest/TestContent.xaml.cs b/Fluent.Ribbon.Showcase/TestContent.xaml.cs similarity index 93% rename from FluentTest/TestContent.xaml.cs rename to Fluent.Ribbon.Showcase/TestContent.xaml.cs index cd7ff9b6b..c0c4867d2 100644 --- a/FluentTest/TestContent.xaml.cs +++ b/Fluent.Ribbon.Showcase/TestContent.xaml.cs @@ -1,450 +1,461 @@ -namespace FluentTest -{ - using System; - using System.Diagnostics; - using System.Linq; - using System.Text; - using System.Threading; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Input; - using System.Windows.Media; - using System.Windows.Media.Imaging; - using System.Windows.Threading; - using Fluent; - using FluentTest.ViewModels; - using Button = Fluent.Button; - - public partial class TestContent - { - private Theme? currentTheme; - private readonly MainViewModel viewModel; - - public TestContent() - { - this.InitializeComponent(); - - //Ribbon.Localization.Culture = new CultureInfo("ru-RU"); - - this.HookEvents(); - - this.viewModel = new MainViewModel(); - this.DataContext = this.viewModel; - } - - private void HookEvents() - { - this.Loaded += this.HandleTestContentLoaded; - - this.buttonBold.Checked += (s, e) => Debug.WriteLine("Checked"); - this.buttonBold.Unchecked += (s, e) => Debug.WriteLine("Unchecked"); - - this.PreviewMouseWheel += this.OnPreviewMouseWheel; - } - - private static void OnScreenTipHelpPressed(object sender, ScreenTipHelpEventArgs e) - { - Process.Start((string)e.HelpTopic); - } - - private void HandleTestContentLoaded(object sender, RoutedEventArgs e) - { - ScreenTip.HelpPressed += OnScreenTipHelpPressed; - } - - private void OnLauncherButtonClick(object sender, RoutedEventArgs e) - { - var groupBox = (RibbonGroupBox)sender; - - var wnd = new Window - { - Content = string.Format("Launcher-Window for: {0}", groupBox.Header), - Owner = Window.GetWindow(this) - }; - - wnd.Show(); - } - - private void OnSplitClick(object sender, RoutedEventArgs e) - { - MessageBox.Show("Split Clicked!!!"); - } - - private void OnEnlargeClick(object sender, RoutedEventArgs e) - { - this.InRibbonGallery.Enlarge(); - } - - private void OnReduceClick(object sender, RoutedEventArgs e) - { - this.InRibbonGallery.Reduce(); - } - - public Button CreateRibbonButton() - { - var fooCommand1 = new TestRoutedCommand(); - - var button = new Button - { - Command = fooCommand1.ItemCommand, - Header = "Foo", - Icon = new BitmapImage(new Uri(@"Images\Green.png", UriKind.Relative)), - LargeIcon = new BitmapImage(new Uri(@"Images\GreenLarge.png", UriKind.Relative)), - }; - - this.CommandBindings.Add(fooCommand1.ItemCommandBinding); - return button; - } - - #region Theming - - private enum Theme - { - Office2010, - Office2013, - Windows8 - } - - private void OnOffice2013Click(object sender, RoutedEventArgs e) - { - this.ChangeTheme(Theme.Office2013, "pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml"); - } - - private void OnOffice2010SilverClick(object sender, RoutedEventArgs e) - { - this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Silver.xaml"); - } - - private void OnOffice2010BlackClick(object sender, RoutedEventArgs e) - { - this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Black.xaml"); - } - - private void OnOffice2010BlueClick(object sender, RoutedEventArgs e) - { - this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Blue.xaml"); - } - - private void OnWindows8Click(object sender, RoutedEventArgs e) - { - this.ChangeTheme(Theme.Windows8, "pack://application:,,,/Fluent;component/Themes/Windows8/Silver.xaml"); - } - - - private void ChangeTheme(Theme theme, string color) - { - this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() => - { - var owner = Window.GetWindow(this); - if (owner != null) - { - owner.Resources.BeginInit(); - - if (owner.Resources.MergedDictionaries.Count > 0) - { - owner.Resources.MergedDictionaries.RemoveAt(0); - } - - if (string.IsNullOrEmpty(color) == false) - { - owner.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri(color) }); - } - - owner.Resources.EndInit(); - } - - if (this.currentTheme != theme) - { - Application.Current.Resources.BeginInit(); - switch (theme) - { - case Theme.Office2010: - Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Generic.xaml") }); - Application.Current.Resources.MergedDictionaries.RemoveAt(0); - break; - case Theme.Office2013: - Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml") }); - Application.Current.Resources.MergedDictionaries.RemoveAt(0); - break; - case Theme.Windows8: - Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Windows8/Generic.xaml") }); - Application.Current.Resources.MergedDictionaries.RemoveAt(0); - break; - } - - this.currentTheme = theme; - Application.Current.Resources.EndInit(); - - if (owner is RibbonWindow) - { - owner.Style = null; - owner.Style = owner.FindResource("RibbonWindowStyle") as Style; - owner.Style = null; - - // Resize Window to work around alignment issues caused by theme change - ++owner.Width; - --owner.Width; - } - } - })); - } - - private void HandleDontUseDwmClick(object sender, RoutedEventArgs e) - { - var control = sender as UIElement; - - if (control == null) - { - return; - } - - var window = Window.GetWindow(control) as RibbonWindow; - - if (window == null) - { - return; - } - - window.DontUseDwm = this.DontUseDwm.IsChecked.GetValueOrDefault(); - } - - #endregion Theming - - #region Logical tree - - private void OnShowLogicalTreeClick(object sender, RoutedEventArgs e) - { - this.CheckLogicalTree(this.ribbon); - this.logicalTreeView.Items.Clear(); - this.BuildLogicalTree(this.ribbon, this.logicalTreeView); - } - - private static string GetDebugInfo(DependencyObject element) - { - if (element == null) - { - return "NULL"; - } - - var ribbonControl = element as IHeaderedControl; - - var header = ribbonControl != null - ? ribbonControl.Header - : string.Empty; - - var frameworkElement = element as FrameworkElement; - var name = frameworkElement != null - ? frameworkElement.Name - : string.Empty; - - return string.Format("[{0}] (Header: {1} || Name: {2})", element, header, name); - } - - private void CheckLogicalTree(DependencyObject root) - { - var children = LogicalTreeHelper.GetChildren(root); - foreach (var child in children.OfType()) - { - if (LogicalTreeHelper.GetParent(child) != root) - { - Debug.WriteLine(string.Format("Incorrect logical parent for {0}", GetDebugInfo(child))); - Debug.WriteLine(string.Format("\tExpected: {0}", GetDebugInfo(root))); - Debug.WriteLine(string.Format("\tFound: {0}", GetDebugInfo(LogicalTreeHelper.GetParent(child)))); - } - - this.CheckLogicalTree(child); - } - } - - private void BuildLogicalTree(DependencyObject current, ItemsControl parentControl) - { - var newItem = new TreeViewItem - { - Header = GetDebugInfo(current), - Tag = current - }; - - parentControl.Items.Add(newItem); - - var children = LogicalTreeHelper.GetChildren(current); - foreach (var child in children.OfType()) - { - this.BuildLogicalTree(child, newItem); - } - } - - private void OnTreeDoubleClick(object sender, MouseButtonEventArgs e) - { - var treeView = sender as TreeView; - - if (treeView == null) - { - return; - } - - var item = treeView.SelectedItem as TreeViewItem; - if (item == null) - { - return; - } - - var stringBuilder = new StringBuilder(); - this.BuildBackLogicalTree(item.Tag as DependencyObject, stringBuilder); - - MessageBox.Show(string.Format("From buttom to top:\n{0}", stringBuilder)); - } - - private void BuildBackLogicalTree(DependencyObject current, StringBuilder stringBuilder) - { - if (current == null - || current == this.ribbon) - { - return; - } - - stringBuilder.AppendFormat(" -> {0}\n", GetDebugInfo(current)); - - var parent = LogicalTreeHelper.GetParent(current); - - this.BuildBackLogicalTree(parent, stringBuilder); - } - - #endregion Logical tree - - private void OnFormatPainterClick(object sender, RoutedEventArgs e) - { - MessageBox.Show("FP"); - } - - private void OnHelpClick(object sender, RoutedEventArgs e) - { - if (this.tabGroup1.Visibility == Visibility.Visible) - { - this.tabGroup1.Visibility = Visibility.Collapsed; - this.tabGroup2.Visibility = Visibility.Collapsed; - } - else - { - this.tabGroup1.Visibility = Visibility.Visible; - this.tabGroup2.Visibility = Visibility.Visible; - } - } - - private void OnSpinnerValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - // MessageBox.Show(String.Format("Changed from {0} to {1}", e.OldValue, e.NewValue)); - } - - private void OnMenuItemClick(object sender, RoutedEventArgs e) - { - var wnd = new TestWindow - { - Owner = Window.GetWindow(this) - }; - wnd.Show(); - } - - private void OnPrintVisualClick(object sender, RoutedEventArgs e) - { - var printDlg = new PrintDialog(); - - if (printDlg.ShowDialog() == true) - { - printDlg.PrintVisual(this, "Main Window"); - } - } - - private void AddRibbonTab_OnClick(object sender, RoutedEventArgs e) - { - var tab = new RibbonTabItem - { - Header = "Test" - }; - - var group = new RibbonGroupBox(); - for (var i = 0; i < 20; i++) - { - group.Items.Add(this.CreateRibbonButton()); - } - - tab.Groups.Add(group); - - this.ribbon.Tabs.Add(tab); - } - - private void HandleSaveAsClick(object sender, RoutedEventArgs e) - { - var w = new Window(); - w.ShowDialog(); - } - - private void OpenRegularWindow_OnClick(object sender, RoutedEventArgs e) - { - new RegularWindow().Show(); - } - - private void OpenMahMetroWindow_OnClick(object sender, RoutedEventArgs e) - { - new MahMetroWindow().Show(); - } - - private void OpenRibbonWindowWithoutVisibileRibbon_OnClick(object sender, RoutedEventArgs e) - { - new RibbonWindowWithoutRibbon().Show(); - } - - private void ZoomSlider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs e) - { - var textFormattingMode = e.NewValue > 1.0 || Math.Abs(e.NewValue - 1.0) < double.Epsilon ? TextFormattingMode.Ideal : TextFormattingMode.Display; - TextOptions.SetTextFormattingMode(this, textFormattingMode); - } - - private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) == false - && Keyboard.IsKeyDown(Key.RightCtrl) == false) - { - return; - } - - this.zoomSlider.Value += e.Delta > 0 ? 0.1 : -0.1; - - e.Handled = true; - } - - private void SleepButton_OnClick(object sender, RoutedEventArgs e) - { - Thread.Sleep(TimeSpan.FromSeconds(10)); - } - - private void OpenModalRibbonWindow_OnClick(object sender, RoutedEventArgs e) - { - new TestWindow().ShowDialog(); - } - } - - public class TestRoutedCommand - { - public static RoutedCommand TestPresenterCommand = new RoutedCommand("TestPresenterCommand", typeof(TestRoutedCommand)); - - public ICommand ItemCommand - { - get { return TestPresenterCommand; } - } - - public CommandBinding ItemCommandBinding - { - get { return new CommandBinding(TestPresenterCommand, this.OnTestCommandExecuted, this.CanExecuteTestCommand); } - } - - private void CanExecuteTestCommand(object sender, CanExecuteRoutedEventArgs e) - { - e.CanExecute = true; - } - - private void OnTestCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - MessageBox.Show("TestPresenterCommand"); - } - } +namespace FluentTest +{ + using System; + using System.Diagnostics; + using System.Linq; + using System.Text; + using System.Threading; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + using System.Windows.Media; + using System.Windows.Media.Imaging; + using System.Windows.Threading; + using Fluent; + using FluentTest.ViewModels; + using Button = Fluent.Button; + + public partial class TestContent + { + private Theme? currentTheme; + private readonly MainViewModel viewModel; + + public TestContent() + { + this.InitializeComponent(); + + //Ribbon.Localization.Culture = new CultureInfo("ru-RU"); + + this.HookEvents(); + + this.viewModel = new MainViewModel(); + this.DataContext = this.viewModel; + } + + private void HookEvents() + { + this.Loaded += this.HandleTestContentLoaded; + + this.buttonBold.Checked += (s, e) => Debug.WriteLine("Checked"); + this.buttonBold.Unchecked += (s, e) => Debug.WriteLine("Unchecked"); + + this.PreviewMouseWheel += this.OnPreviewMouseWheel; + } + + private static void OnScreenTipHelpPressed(object sender, ScreenTipHelpEventArgs e) + { + Process.Start((string)e.HelpTopic); + } + + private void HandleTestContentLoaded(object sender, RoutedEventArgs e) + { + ScreenTip.HelpPressed += OnScreenTipHelpPressed; + } + + private void OnLauncherButtonClick(object sender, RoutedEventArgs e) + { + var groupBox = (RibbonGroupBox)sender; + + var wnd = new Window + { + Content = string.Format("Launcher-Window for: {0}", groupBox.Header), + Owner = Window.GetWindow(this) + }; + + wnd.Show(); + } + + private void OnSplitClick(object sender, RoutedEventArgs e) + { + MessageBox.Show("Split Clicked!!!"); + } + + private void OnEnlargeClick(object sender, RoutedEventArgs e) + { + this.InRibbonGallery.Enlarge(); + } + + private void OnReduceClick(object sender, RoutedEventArgs e) + { + this.InRibbonGallery.Reduce(); + } + + public Button CreateRibbonButton() + { + var fooCommand1 = new TestRoutedCommand(); + + var button = new Button + { + Command = fooCommand1.ItemCommand, + Header = "Foo", + Icon = new BitmapImage(new Uri(@"pack://application:,,,/Fluent.Ribbon.Showcase;component/Images/Green.png", UriKind.Absolute)), + LargeIcon = new BitmapImage(new Uri(@"pack://application:,,,/Fluent.Ribbon.Showcase;component/Images/GreenLarge.png", UriKind.Absolute)), + }; + + this.CommandBindings.Add(fooCommand1.ItemCommandBinding); + return button; + } + + #region Theming + + private enum Theme + { + Office2010, + Office2013, + Windows8 + } + + private void OnOffice2013Click(object sender, RoutedEventArgs e) + { + this.ChangeTheme(Theme.Office2013, "pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml"); + } + + private void OnOffice2010SilverClick(object sender, RoutedEventArgs e) + { + this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Silver.xaml"); + } + + private void OnOffice2010BlackClick(object sender, RoutedEventArgs e) + { + this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Black.xaml"); + } + + private void OnOffice2010BlueClick(object sender, RoutedEventArgs e) + { + this.ChangeTheme(Theme.Office2010, "pack://application:,,,/Fluent;component/Themes/Office2010/Blue.xaml"); + } + + private void OnWindows8Click(object sender, RoutedEventArgs e) + { + this.ChangeTheme(Theme.Windows8, "pack://application:,,,/Fluent;component/Themes/Windows8/Silver.xaml"); + } + + + private void ChangeTheme(Theme theme, string color) + { + this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() => + { + var owner = Window.GetWindow(this); + if (owner != null) + { + owner.Resources.BeginInit(); + + if (owner.Resources.MergedDictionaries.Count > 0) + { + owner.Resources.MergedDictionaries.RemoveAt(0); + } + + if (string.IsNullOrEmpty(color) == false) + { + owner.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri(color) }); + } + + owner.Resources.EndInit(); + } + + if (this.currentTheme != theme) + { + Application.Current.Resources.BeginInit(); + switch (theme) + { + case Theme.Office2010: + Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Generic.xaml") }); + Application.Current.Resources.MergedDictionaries.RemoveAt(0); + break; + case Theme.Office2013: + Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Office2013/Generic.xaml") }); + Application.Current.Resources.MergedDictionaries.RemoveAt(0); + break; + case Theme.Windows8: + Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary { Source = new Uri("pack://application:,,,/Fluent;component/Themes/Windows8/Generic.xaml") }); + Application.Current.Resources.MergedDictionaries.RemoveAt(0); + break; + } + + this.currentTheme = theme; + Application.Current.Resources.EndInit(); + + if (owner is RibbonWindow) + { + owner.Style = null; + owner.Style = owner.FindResource("RibbonWindowStyle") as Style; + owner.Style = null; + + // Resize Window to work around alignment issues caused by theme change + ++owner.Width; + --owner.Width; + } + } + })); + } + + private void HandleDontUseDwmClick(object sender, RoutedEventArgs e) + { + var control = sender as UIElement; + + if (control == null) + { + return; + } + + var window = Window.GetWindow(control) as RibbonWindow; + + if (window == null) + { + return; + } + + window.DontUseDwm = this.DontUseDwm.IsChecked.GetValueOrDefault(); + } + + #endregion Theming + + #region Logical tree + + private void OnShowLogicalTreeClick(object sender, RoutedEventArgs e) + { + this.CheckLogicalTree(this.ribbon); + this.logicalTreeView.Items.Clear(); + this.BuildLogicalTree(this.ribbon, this.logicalTreeView); + } + + private static string GetDebugInfo(DependencyObject element) + { + if (element == null) + { + return "NULL"; + } + + var ribbonControl = element as IHeaderedControl; + + var header = ribbonControl != null + ? ribbonControl.Header + : string.Empty; + + var frameworkElement = element as FrameworkElement; + var name = frameworkElement != null + ? frameworkElement.Name + : string.Empty; + + return string.Format("[{0}] (Header: {1} || Name: {2})", element, header, name); + } + + private void CheckLogicalTree(DependencyObject root) + { + var children = LogicalTreeHelper.GetChildren(root); + foreach (var child in children.OfType()) + { + if (LogicalTreeHelper.GetParent(child) != root) + { + Debug.WriteLine(string.Format("Incorrect logical parent for {0}", GetDebugInfo(child))); + Debug.WriteLine(string.Format("\tExpected: {0}", GetDebugInfo(root))); + Debug.WriteLine(string.Format("\tFound: {0}", GetDebugInfo(LogicalTreeHelper.GetParent(child)))); + } + + this.CheckLogicalTree(child); + } + } + + private void BuildLogicalTree(DependencyObject current, ItemsControl parentControl) + { + var newItem = new TreeViewItem + { + Header = GetDebugInfo(current), + Tag = current + }; + + parentControl.Items.Add(newItem); + + var children = LogicalTreeHelper.GetChildren(current); + foreach (var child in children.OfType()) + { + this.BuildLogicalTree(child, newItem); + } + } + + private void OnTreeDoubleClick(object sender, MouseButtonEventArgs e) + { + var treeView = sender as TreeView; + + if (treeView == null) + { + return; + } + + var item = treeView.SelectedItem as TreeViewItem; + if (item == null) + { + return; + } + + var stringBuilder = new StringBuilder(); + this.BuildBackLogicalTree(item.Tag as DependencyObject, stringBuilder); + + MessageBox.Show(string.Format("From buttom to top:\n{0}", stringBuilder)); + } + + private void BuildBackLogicalTree(DependencyObject current, StringBuilder stringBuilder) + { + if (current == null + || current == this.ribbon) + { + return; + } + + stringBuilder.AppendFormat(" -> {0}\n", GetDebugInfo(current)); + + var parent = LogicalTreeHelper.GetParent(current); + + this.BuildBackLogicalTree(parent, stringBuilder); + } + + #endregion Logical tree + + private void OnFormatPainterClick(object sender, RoutedEventArgs e) + { + MessageBox.Show("FP"); + } + + private void OnHelpClick(object sender, RoutedEventArgs e) + { + if (this.tabGroup1.Visibility == Visibility.Visible) + { + this.tabGroup1.Visibility = Visibility.Collapsed; + this.tabGroup2.Visibility = Visibility.Collapsed; + } + else + { + this.tabGroup1.Visibility = Visibility.Visible; + this.tabGroup2.Visibility = Visibility.Visible; + } + } + + private void OnSpinnerValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + // MessageBox.Show(String.Format("Changed from {0} to {1}", e.OldValue, e.NewValue)); + } + + private void OnMenuItemClick(object sender, RoutedEventArgs e) + { + var wnd = new TestWindow + { + Owner = Window.GetWindow(this) + }; + wnd.Show(); + } + + private void OnPrintVisualClick(object sender, RoutedEventArgs e) + { + var printDlg = new PrintDialog(); + + if (printDlg.ShowDialog() == true) + { + printDlg.PrintVisual(this, "Main Window"); + } + } + + private void AddRibbonTab_OnClick(object sender, RoutedEventArgs e) + { + var tab = new RibbonTabItem + { + Header = "Test" + }; + + var group = new RibbonGroupBox(); + for (var i = 0; i < 20; i++) + { + group.Items.Add(this.CreateRibbonButton()); + } + + tab.Groups.Add(group); + + this.ribbon.Tabs.Add(tab); + } + + private void HandleSaveAsClick(object sender, RoutedEventArgs e) + { + var w = new Window(); + w.ShowDialog(); + } + + private void OpenRegularWindow_OnClick(object sender, RoutedEventArgs e) + { + new RegularWindow().Show(); + } + + private void OpenMahMetroWindow_OnClick(object sender, RoutedEventArgs e) + { + new MahMetroWindow().Show(); + } + + private void OpenRibbonWindowWithoutVisibileRibbon_OnClick(object sender, RoutedEventArgs e) + { + new RibbonWindowWithoutRibbon().Show(); + } + + private void ZoomSlider_OnValueChanged(object sender, RoutedPropertyChangedEventArgs e) + { + var textFormattingMode = e.NewValue > 1.0 || Math.Abs(e.NewValue - 1.0) < double.Epsilon ? TextFormattingMode.Ideal : TextFormattingMode.Display; + TextOptions.SetTextFormattingMode(this, textFormattingMode); + } + + private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) == false + && Keyboard.IsKeyDown(Key.RightCtrl) == false) + { + return; + } + + this.zoomSlider.Value += e.Delta > 0 ? 0.1 : -0.1; + + e.Handled = true; + } + + private void SleepButton_OnClick(object sender, RoutedEventArgs e) + { + Thread.Sleep(TimeSpan.FromSeconds(10)); + } + + private void OpenModalRibbonWindow_OnClick(object sender, RoutedEventArgs e) + { + new TestWindow().ShowDialog(); + } + + private void ShowStartScreen_OnClick(object sender, RoutedEventArgs e) + { + this.startScreen.Shown = false; + this.startScreen.IsOpen = true; + } + + private void HandleAddItemToFontsClick(object sender, RoutedEventArgs e) + { + this.viewModel.FontsViewModel.FontsData.Add($"Added item {this.viewModel.FontsViewModel.FontsData.Count}"); + } + } + + public class TestRoutedCommand + { + public static RoutedCommand TestPresenterCommand = new RoutedCommand("TestPresenterCommand", typeof(TestRoutedCommand)); + + public ICommand ItemCommand + { + get { return TestPresenterCommand; } + } + + public CommandBinding ItemCommandBinding + { + get { return new CommandBinding(TestPresenterCommand, this.OnTestCommandExecuted, this.CanExecuteTestCommand); } + } + + private void CanExecuteTestCommand(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = true; + } + + private void OnTestCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + MessageBox.Show("TestPresenterCommand"); + } + } } \ No newline at end of file diff --git a/FluentTest/TestWindow.xaml b/Fluent.Ribbon.Showcase/TestWindow.xaml similarity index 98% rename from FluentTest/TestWindow.xaml rename to Fluent.Ribbon.Showcase/TestWindow.xaml index 06dfb7273..5bed141c0 100644 --- a/FluentTest/TestWindow.xaml +++ b/Fluent.Ribbon.Showcase/TestWindow.xaml @@ -1,18 +1,18 @@ - - + + \ No newline at end of file diff --git a/FluentTest/TestWindow.xaml.cs b/Fluent.Ribbon.Showcase/TestWindow.xaml.cs similarity index 95% rename from FluentTest/TestWindow.xaml.cs rename to Fluent.Ribbon.Showcase/TestWindow.xaml.cs index 9ae19b228..4fe7cf42e 100644 --- a/FluentTest/TestWindow.xaml.cs +++ b/Fluent.Ribbon.Showcase/TestWindow.xaml.cs @@ -1,13 +1,13 @@ -namespace FluentTest -{ - /// - /// Interaction logic for TestWindow.xaml - /// - public partial class TestWindow - { - public TestWindow() - { - this.InitializeComponent(); - } - } +namespace FluentTest +{ + /// + /// Interaction logic for TestWindow.xaml + /// + public partial class TestWindow + { + public TestWindow() + { + this.InitializeComponent(); + } + } } \ No newline at end of file diff --git a/FluentTest/ViewModels/ColorViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs similarity index 57% rename from FluentTest/ViewModels/ColorViewModel.cs rename to Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs index 32bb218e0..a2b6c37f4 100644 --- a/FluentTest/ViewModels/ColorViewModel.cs +++ b/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs @@ -1,55 +1,49 @@ -namespace FluentTest.ViewModels -{ - using System.Windows.Media; - - public class ColorViewModel : ViewModel - { - private Color standardColor; - private Color highlightColor; - - private readonly Color[] themeColors = { Colors.Red, Colors.Green, Colors.Blue, Colors.White, Colors.Black, Colors.Purple }; - private Color themeColor; - - public ColorViewModel() - { - this.StandardColor = Colors.Black; - this.HighlightColor = Colors.Yellow; - this.ThemeColor = Colors.Blue; - } - - public Color StandardColor - { - get { return this.standardColor; } - set - { - this.standardColor = value; - this.OnPropertyChanged("StandardColor"); - } - } - - public Color HighlightColor - { - get { return this.highlightColor; } - set - { - this.highlightColor = value; - this.OnPropertyChanged("HighlightColor"); - } - } - - public Color[] ThemeColors - { - get { return this.themeColors; } - } - - public Color ThemeColor - { - get { return this.themeColor; } - set - { - this.themeColor = value; - this.OnPropertyChanged("ThemeColor"); - } - } - } +namespace FluentTest.ViewModels +{ + using System.Windows; + using System.Windows.Media; + + public class ColorViewModel : ViewModel + { + private Color standardColor; + private Color highlightColor; + + public ColorViewModel() + { + this.StandardColor = Colors.Black; + this.HighlightColor = Colors.Yellow; + } + + public Color StandardColor + { + get { return this.standardColor; } + set + { + this.standardColor = value; + this.OnPropertyChanged(nameof(this.StandardColor)); + } + } + + public Color HighlightColor + { + get { return this.highlightColor; } + set + { + this.highlightColor = value; + this.OnPropertyChanged(nameof(this.HighlightColor)); + } + } + + public Color[] ThemeColors { get; } = { Colors.Red, Colors.Green, Colors.Blue, Colors.White, Colors.Black, Colors.Purple }; + + public Color ThemeColor + { + get { return ((SolidColorBrush)Application.Current.Resources["RibbonThemeColorBrush"])?.Color ?? Colors.Pink; } + set + { + Application.Current.Resources["RibbonThemeColorBrush"] = new SolidColorBrush(value); + this.OnPropertyChanged(nameof(this.ThemeColor)); + } + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/ViewModels/FontsViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/FontsViewModel.cs new file mode 100644 index 000000000..106faea3d --- /dev/null +++ b/Fluent.Ribbon.Showcase/ViewModels/FontsViewModel.cs @@ -0,0 +1,14 @@ +using System.Collections.ObjectModel; + +namespace FluentTest.ViewModels +{ + public class FontsViewModel : ViewModel + { + private readonly ObservableCollection data = new ObservableCollection { "Tahoma", "Segoe UI", "Arial", "Courier New", "Symbol" }; + + public ObservableCollection FontsData + { + get { return this.data; } + } + } +} diff --git a/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs new file mode 100644 index 000000000..abe9b1e97 --- /dev/null +++ b/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs @@ -0,0 +1,44 @@ +namespace FluentTest.ViewModels +{ + public class GalleryItemViewModel : ViewModel + { + private string text; + private string group; + + public GalleryItemViewModel(string group, string text) + { + this.Group = group; + this.Text = text; + } + + public string Text + { + get { return this.text; } + + set + { + if (value == this.text) + { + return; + } + this.text = value; + this.OnPropertyChanged(nameof(this.Text)); + } + } + + public string Group + { + get { return this.group; } + + set + { + if (value == this.group) + { + return; + } + this.group = value; + this.OnPropertyChanged(nameof(this.Group)); + } + } + } +} \ No newline at end of file diff --git a/FluentTest/ViewModels/GallerySampleDataItemViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/GallerySampleDataItemViewModel.cs similarity index 96% rename from FluentTest/ViewModels/GallerySampleDataItemViewModel.cs rename to Fluent.Ribbon.Showcase/ViewModels/GallerySampleDataItemViewModel.cs index bc57a2a7a..48b1e7e47 100644 --- a/FluentTest/ViewModels/GallerySampleDataItemViewModel.cs +++ b/Fluent.Ribbon.Showcase/ViewModels/GallerySampleDataItemViewModel.cs @@ -1,47 +1,47 @@ -namespace FluentTest.ViewModels -{ - using System; - using System.Windows.Media; - using System.Windows.Media.Imaging; - - public class GallerySampleDataItemViewModel : ViewModel - { - /// - /// Gets or sets icon - /// - public ImageSource Icon { get; set; } - /// - /// Gets or sets large icon - /// - public ImageSource IconLarge { get; set; } - /// - /// Gets or sets text - /// - public string Text { get; set; } - /// - /// Gets or sets group name - /// - public string Group { get; set; } - - /// - /// Creates new item - /// - /// Icon - /// Large Icon - /// Text - /// Group - /// Item - public static GallerySampleDataItemViewModel Create(string icon, string iconLarge, string text, string group) - { - var dataItem = new GallerySampleDataItemViewModel - { - Icon = new BitmapImage(new Uri(icon, UriKind.Relative)), - IconLarge = new BitmapImage(new Uri(iconLarge, UriKind.Relative)), - Text = text, - Group = group - }; - - return dataItem; - } - } +namespace FluentTest.ViewModels +{ + using System; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + public class GallerySampleDataItemViewModel : ViewModel + { + /// + /// Gets or sets icon + /// + public ImageSource Icon { get; set; } + /// + /// Gets or sets large icon + /// + public ImageSource IconLarge { get; set; } + /// + /// Gets or sets text + /// + public string Text { get; set; } + /// + /// Gets or sets group name + /// + public string Group { get; set; } + + /// + /// Creates new item + /// + /// Icon + /// Large Icon + /// Text + /// Group + /// Item + public static GallerySampleDataItemViewModel Create(string icon, string iconLarge, string text, string group) + { + var dataItem = new GallerySampleDataItemViewModel + { + Icon = new BitmapImage(new Uri(icon, UriKind.Relative)), + IconLarge = new BitmapImage(new Uri(iconLarge, UriKind.Relative)), + Text = text, + Group = group + }; + + return dataItem; + } + } } \ No newline at end of file diff --git a/FluentTest/ViewModels/GalleryViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/GalleryViewModel.cs similarity index 67% rename from FluentTest/ViewModels/GalleryViewModel.cs rename to Fluent.Ribbon.Showcase/ViewModels/GalleryViewModel.cs index 4361779a8..793bf6890 100644 --- a/FluentTest/ViewModels/GalleryViewModel.cs +++ b/Fluent.Ribbon.Showcase/ViewModels/GalleryViewModel.cs @@ -1,50 +1,65 @@ -namespace FluentTest.ViewModels -{ - using System.Collections.ObjectModel; - using System.Windows.Input; - using FluentTest.Commanding; - - public class GalleryViewModel : ViewModel - { - private ObservableCollection items; - - public GalleryViewModel() - { - this.Items = new ObservableCollection(); - this.RefreshCommand = new RelayCommand(this.Refresh); - - this.Refresh(); - } - - public ObservableCollection Items - { - get { return this.items; } - private set - { - if (Equals(value, this.items)) return; - this.items = value; - this.OnPropertyChanged("Items"); - } - } - - public ICommand RefreshCommand { get; private set; } - - public void Refresh() - { - this.Items.Clear(); - - this.Items.Add(new GalleryItemViewModel("Group 1", "1")); - this.Items.Add(new GalleryItemViewModel("Group 1", "2")); - this.Items.Add(new GalleryItemViewModel("Group 1", "3")); - this.Items.Add(new GalleryItemViewModel("Group 1", "4")); - this.Items.Add(new GalleryItemViewModel("Group 1", "5")); - this.Items.Add(new GalleryItemViewModel("Group 1", "6")); - this.Items.Add(new GalleryItemViewModel("Group 2", "10")); - this.Items.Add(new GalleryItemViewModel("Group 2", "20")); - this.Items.Add(new GalleryItemViewModel("Group 2", "30")); - this.Items.Add(new GalleryItemViewModel("Group 2", "40")); - this.Items.Add(new GalleryItemViewModel("Group 2", "50")); - this.Items.Add(new GalleryItemViewModel("Group 2", "60")); - } - } +namespace FluentTest.ViewModels +{ + using System.Collections.ObjectModel; + using System.Windows.Input; + using FluentTest.Commanding; + + public class GalleryViewModel : ViewModel + { + private ObservableCollection items; + + public GalleryViewModel() + { + this.Items = new ObservableCollection(); + this.RefreshCommand = new RelayCommand(this.Refresh); + + this.Refresh(); + } + + public ObservableCollection Items + { + get { return this.items; } + private set + { + if (Equals(value, this.items)) return; + this.items = value; + this.OnPropertyChanged("Items"); + } + } + + public ICommand RefreshCommand { get; private set; } + + public void Refresh() + { + this.Items.Clear(); + + this.Items.Add(new GalleryItemViewModel("Group 1", "1")); + this.Items.Add(new GalleryItemViewModel("Group 1", "2")); + this.Items.Add(new GalleryItemViewModel("Group 1", "3")); + this.Items.Add(new GalleryItemViewModel("Group 1", "4")); + this.Items.Add(new GalleryItemViewModel("Group 1", "5")); + this.Items.Add(new GalleryItemViewModel("Group 1", "6")); + + this.Items.Add(new GalleryItemViewModel("Group 2", "10")); + this.Items.Add(new GalleryItemViewModel("Group 2", "20")); + this.Items.Add(new GalleryItemViewModel("Group 2", "30")); + this.Items.Add(new GalleryItemViewModel("Group 2", "40")); + this.Items.Add(new GalleryItemViewModel("Group 2", "50")); + this.Items.Add(new GalleryItemViewModel("Group 2", "60")); + + this.Items.Add(new GalleryItemViewModel("Group 3", "100")); + this.Items.Add(new GalleryItemViewModel("Group 3", "200")); + this.Items.Add(new GalleryItemViewModel("Group 3", "300")); + this.Items.Add(new GalleryItemViewModel("Group 3", "400")); + this.Items.Add(new GalleryItemViewModel("Group 3", "500")); + this.Items.Add(new GalleryItemViewModel("Group 3", "600")); + + this.Items.Add(new GalleryItemViewModel("Group 4", "1000")); + this.Items.Add(new GalleryItemViewModel("Group 4", "2000")); + this.Items.Add(new GalleryItemViewModel("Group 4", "3000")); + this.Items.Add(new GalleryItemViewModel("Group 4", "4000")); + this.Items.Add(new GalleryItemViewModel("Group 4", "5000")); + this.Items.Add(new GalleryItemViewModel("Group 4", "6000")); + } + } } \ No newline at end of file diff --git a/FluentTest/ViewModels/MainViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/MainViewModel.cs similarity index 90% rename from FluentTest/ViewModels/MainViewModel.cs rename to Fluent.Ribbon.Showcase/ViewModels/MainViewModel.cs index 98b17aec6..1b0130f54 100644 --- a/FluentTest/ViewModels/MainViewModel.cs +++ b/Fluent.Ribbon.Showcase/ViewModels/MainViewModel.cs @@ -1,202 +1,202 @@ -namespace FluentTest.ViewModels -{ - using System; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using System.Windows; - using System.Windows.Input; - using Fluent; - using FluentTest.Commanding; - - public class MainViewModel : ViewModel - { - private int boundSpinnerValue; - private ColorViewModel colorViewModel; - private FontsViewModel fontsViewModel; - private GalleryViewModel galleryViewModel; - - private GallerySampleDataItemViewModel[] dataItems; - - private RelayCommand exitCommand; - private double zoom; - private ICommand testCommand; - private string[] manyItems; - private bool? isCheckedToggleButton3; - - public MainViewModel() - { - this.Title = string.Format("Fluent Ribbon Control Suite {0}", GetVersionText()); - this.Zoom = 1.0; - - this.BoundSpinnerValue = 1; - - this.ColorViewModel = new ColorViewModel(); - this.FontsViewModel = new FontsViewModel(); - this.GalleryViewModel = new GalleryViewModel(); - - this.PreviewCommand = new RelayCommand(this.Preview); - this.CancelPreviewCommand = new RelayCommand(this.CancelPreview); - } - - private static string GetVersionText() - { - var version = typeof(Ribbon).Assembly.GetName().Version; - - var attributes = typeof(Ribbon).Assembly - .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false) - as AssemblyInformationalVersionAttribute[]; - - var attrib = attributes.FirstOrDefault(); - - return string.Format("{0} ({1})", version, attrib.InformationalVersion); - } - - private void Preview(GalleryItem galleryItem) - { - Trace.WriteLine(string.Format("Preview: {0}", galleryItem)); - } - - private void CancelPreview(GalleryItem galleryItem) - { - Trace.WriteLine(string.Format("CancelPreview: {0}", galleryItem)); - } - - public string Title { get; private set; } - - public double Zoom - { - get { return this.zoom; } - set - { - if (value.Equals(this.zoom)) return; - this.zoom = value; - this.OnPropertyChanged("Zoom"); - } - } - - public ColorViewModel ColorViewModel - { - get { return this.colorViewModel; } - private set - { - if (Equals(value, this.colorViewModel)) return; - this.colorViewModel = value; - this.OnPropertyChanged("ColorViewModel"); - } - } - - public FontsViewModel FontsViewModel - { - get { return this.fontsViewModel; } - private set - { - if (Equals(value, this.fontsViewModel)) return; - this.fontsViewModel = value; - this.OnPropertyChanged("FontsViewModel"); - } - } - - public GalleryViewModel GalleryViewModel - { - get { return this.galleryViewModel; } - private set - { - if (Equals(value, this.galleryViewModel)) return; - this.galleryViewModel = value; - this.OnPropertyChanged("GalleryViewModel"); - } - } - - /// - /// Gets data items (uses as DataContext) - /// - public GallerySampleDataItemViewModel[] DataItems - { - get - { - return this.dataItems ?? (this.dataItems = new[] - { - GallerySampleDataItemViewModel.Create("Images\\Blue.png", "Images\\BlueLarge.png", "Blue", "Group A"), - GallerySampleDataItemViewModel.Create("Images\\Brown.png", "Images\\BrownLarge.png", "Brown", "Group A"), - GallerySampleDataItemViewModel.Create("Images\\Gray.png", "Images\\GrayLarge.png", "Gray", "Group A"), - GallerySampleDataItemViewModel.Create("Images\\Green.png", "Images\\GreenLarge.png", "Green", "Group A"), - GallerySampleDataItemViewModel.Create("Images\\Orange.png", "Images\\OrangeLarge.png", "Orange", "Group A"), - GallerySampleDataItemViewModel.Create("Images\\Pink.png", "Images\\PinkLarge.png", "Pink", "Group B"), - GallerySampleDataItemViewModel.Create("Images\\Red.png", "Images\\RedLarge.png", "Red", "Group B"), - GallerySampleDataItemViewModel.Create("Images\\Yellow.png", "Images\\YellowLarge.png", "Yellow", "Group B") - }); - } - } - - public string[] ManyItems - { - get { return this.manyItems ?? (this.manyItems = this.GenerateStrings(5000)); } - } - - public bool? IsCheckedToggleButton3 - { - get { return this.isCheckedToggleButton3; } - set - { - if (this.isCheckedToggleButton3 != value) - { - this.isCheckedToggleButton3 = value; - this.OnPropertyChanged("ToggleButton3IsChecked"); - } - } - } - - private string[] GenerateStrings(int count) - { - return Enumerable.Repeat("Test", count).ToArray(); - } - - public ICommand PreviewCommand { get; private set; } - - public ICommand CancelPreviewCommand { get; private set; } - - public int BoundSpinnerValue - { - get { return this.boundSpinnerValue; } - set - { - this.boundSpinnerValue = value; - this.OnPropertyChanged("BoundSpinnerValue"); - } - } - - #region Exit - - /// - /// Exit from the application - /// - public ICommand ExitCommand - { - get - { - if (this.exitCommand == null) - { - this.exitCommand = new RelayCommand(Application.Current.Shutdown, () => this.BoundSpinnerValue > 0); - } - - return this.exitCommand; - } - } - - #endregion - - public ICommand TestCommand - { - get - { - if (this.testCommand == null) - { - this.testCommand = new RelayCommand(() => MessageBox.Show("Test-Command")); - } - - return this.testCommand; - } - } - } +namespace FluentTest.ViewModels +{ + using System; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Windows; + using System.Windows.Input; + using Fluent; + using FluentTest.Commanding; + + public class MainViewModel : ViewModel + { + private int boundSpinnerValue; + private ColorViewModel colorViewModel; + private FontsViewModel fontsViewModel; + private GalleryViewModel galleryViewModel; + + private GallerySampleDataItemViewModel[] dataItems; + + private RelayCommand exitCommand; + private double zoom; + private ICommand testCommand; + private string[] manyItems; + private bool? isCheckedToggleButton3; + + public MainViewModel() + { + this.Title = string.Format("Fluent.Ribbon {0}", GetVersionText()); + this.Zoom = 1.0; + + this.BoundSpinnerValue = 1; + + this.ColorViewModel = new ColorViewModel(); + this.FontsViewModel = new FontsViewModel(); + this.GalleryViewModel = new GalleryViewModel(); + + this.PreviewCommand = new RelayCommand(this.Preview); + this.CancelPreviewCommand = new RelayCommand(this.CancelPreview); + } + + private static string GetVersionText() + { + var version = typeof(Ribbon).Assembly.GetName().Version; + + var attributes = typeof(Ribbon).Assembly + .GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false) + as AssemblyInformationalVersionAttribute[]; + + var attrib = attributes.FirstOrDefault(); + + return string.Format("{0} ({1})", version, attrib.InformationalVersion); + } + + private void Preview(GalleryItem galleryItem) + { + Trace.WriteLine(string.Format("Preview: {0}", galleryItem)); + } + + private void CancelPreview(GalleryItem galleryItem) + { + Trace.WriteLine(string.Format("CancelPreview: {0}", galleryItem)); + } + + public string Title { get; private set; } + + public double Zoom + { + get { return this.zoom; } + set + { + if (value.Equals(this.zoom)) return; + this.zoom = value; + this.OnPropertyChanged("Zoom"); + } + } + + public ColorViewModel ColorViewModel + { + get { return this.colorViewModel; } + private set + { + if (Equals(value, this.colorViewModel)) return; + this.colorViewModel = value; + this.OnPropertyChanged("ColorViewModel"); + } + } + + public FontsViewModel FontsViewModel + { + get { return this.fontsViewModel; } + private set + { + if (Equals(value, this.fontsViewModel)) return; + this.fontsViewModel = value; + this.OnPropertyChanged("FontsViewModel"); + } + } + + public GalleryViewModel GalleryViewModel + { + get { return this.galleryViewModel; } + private set + { + if (Equals(value, this.galleryViewModel)) return; + this.galleryViewModel = value; + this.OnPropertyChanged("GalleryViewModel"); + } + } + + /// + /// Gets data items (uses as DataContext) + /// + public GallerySampleDataItemViewModel[] DataItems + { + get + { + return this.dataItems ?? (this.dataItems = new[] + { + GallerySampleDataItemViewModel.Create("Images\\Blue.png", "Images\\BlueLarge.png", "Blue", "Group A"), + GallerySampleDataItemViewModel.Create("Images\\Brown.png", "Images\\BrownLarge.png", "Brown", "Group A"), + GallerySampleDataItemViewModel.Create("Images\\Gray.png", "Images\\GrayLarge.png", "Gray", "Group A"), + GallerySampleDataItemViewModel.Create("Images\\Green.png", "Images\\GreenLarge.png", "Green", "Group A"), + GallerySampleDataItemViewModel.Create("Images\\Orange.png", "Images\\OrangeLarge.png", "Orange", "Group A"), + GallerySampleDataItemViewModel.Create("Images\\Pink.png", "Images\\PinkLarge.png", "Pink", "Group B"), + GallerySampleDataItemViewModel.Create("Images\\Red.png", "Images\\RedLarge.png", "Red", "Group B"), + GallerySampleDataItemViewModel.Create("Images\\Yellow.png", "Images\\YellowLarge.png", "Yellow", "Group B") + }); + } + } + + public string[] ManyItems + { + get { return this.manyItems ?? (this.manyItems = this.GenerateStrings(5000)); } + } + + public bool? IsCheckedToggleButton3 + { + get { return this.isCheckedToggleButton3; } + set + { + if (this.isCheckedToggleButton3 != value) + { + this.isCheckedToggleButton3 = value; + this.OnPropertyChanged("ToggleButton3IsChecked"); + } + } + } + + private string[] GenerateStrings(int count) + { + return Enumerable.Repeat("Test", count).ToArray(); + } + + public ICommand PreviewCommand { get; private set; } + + public ICommand CancelPreviewCommand { get; private set; } + + public int BoundSpinnerValue + { + get { return this.boundSpinnerValue; } + set + { + this.boundSpinnerValue = value; + this.OnPropertyChanged("BoundSpinnerValue"); + } + } + + #region Exit + + /// + /// Exit from the application + /// + public ICommand ExitCommand + { + get + { + if (this.exitCommand == null) + { + this.exitCommand = new RelayCommand(Application.Current.Shutdown, () => this.BoundSpinnerValue > 0); + } + + return this.exitCommand; + } + } + + #endregion + + public ICommand TestCommand + { + get + { + if (this.testCommand == null) + { + this.testCommand = new RelayCommand(() => MessageBox.Show("Test-Command")); + } + + return this.testCommand; + } + } + } } \ No newline at end of file diff --git a/FluentTest/ViewModels/ViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs similarity index 67% rename from FluentTest/ViewModels/ViewModel.cs rename to Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs index d8b41ada0..8c2b0757b 100644 --- a/FluentTest/ViewModels/ViewModel.cs +++ b/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs @@ -1,19 +1,16 @@ -namespace FluentTest.ViewModels -{ - using System.ComponentModel; - using JetBrains.Annotations; - - public class ViewModel : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged = delegate { }; - - [NotifyPropertyChangedInvocator] - protected void OnPropertyChanged(string propertyName) - { - if (this.PropertyChanged != null) - { - this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - } +namespace FluentTest.ViewModels +{ + using System.ComponentModel; + using JetBrains.Annotations; + + public class ViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged = delegate { }; + + [NotifyPropertyChangedInvocator] + protected void OnPropertyChanged(string propertyName) + { + this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/app.manifest b/Fluent.Ribbon.Showcase/app.manifest new file mode 100644 index 000000000..f4c957041 --- /dev/null +++ b/Fluent.Ribbon.Showcase/app.manifest @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon.Showcase/packages.config b/Fluent.Ribbon.Showcase/packages.config new file mode 100644 index 000000000..8cda12d03 --- /dev/null +++ b/Fluent.Ribbon.Showcase/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Fluent.Ribbon.msbuild b/Fluent.Ribbon.msbuild index 217cbc171..e75fb0e53 100644 --- a/Fluent.Ribbon.msbuild +++ b/Fluent.Ribbon.msbuild @@ -31,8 +31,6 @@ - - diff --git a/Fluent.Ribbon.nuspec b/Fluent.Ribbon.nuspec index 67a879471..83decc863 100644 --- a/Fluent.Ribbon.nuspec +++ b/Fluent.Ribbon.nuspec @@ -3,27 +3,27 @@ Fluent.Ribbon $Version$ - Fluent Ribbon Control Suite - Fluent Ribbon Control Suite is a library that implements an Office-like Ribbon for WPF. - Fluent Ribbon Control Suite is a library that implements an Office-like user interface for the Windows Presentation Foundation (WPF). It provides well-customized controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. It is bundled with the most up-to-date Office 2010, Office 2013 and Windows 8 styles. + Fluent.Ribbon + Fluent.Ribbon is a library that implements an Office-like Ribbon for WPF. + Fluent.Ribbon is a library that implements an Office-like user interface for the Windows Presentation Foundation (WPF). It provides controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. It is bundled with Office 2010, Office 2013 and Windows 8 themes. You can read the changelog at: https://github.com/fluentribbon/Fluent.Ribbon/blob/master/Changelog.md - daVinci,SableRaven,batzen,LastElb,firehirsch + batzen https://github.com/fluentribbon/Fluent.Ribbon/blob/master/License.txt https://github.com/fluentribbon/Fluent.Ribbon https://raw.githubusercontent.com/fluentribbon/Fluent.Ribbon/master/Images/Logo/Logo_32x32.png false - ribbon fluent ribbonwindow office2010 office2013 windows8 backstage + ribbon fluent ribbon ribbonwindow office2010 office2013 windows8 backstage + + + - - - - + \ No newline at end of file diff --git a/Fluent.Ribbon.sln b/Fluent.Ribbon.sln index 2e4c032aa..51e330fff 100644 --- a/Fluent.Ribbon.sln +++ b/Fluent.Ribbon.sln @@ -1,26 +1,18 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentTest dotNET 4.5", "FluentTest\FluentTest dotNET 4.5.csproj", "{2C2A076B-E626-4A07-9D6E-4AEE3FEC41B6}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent.Ribbon.Showcase.NET 4.5", "Fluent.Ribbon.Showcase\Fluent.Ribbon.Showcase.NET 4.5.csproj", "{2C2A076B-E626-4A07-9D6E-4AEE3FEC41B6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent dotNET 4.5", "Fluent\Fluent dotNET 4.5.csproj", "{4C92FCF4-3561-499F-BC5B-F2F089863047}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent.Ribbon.NET 4.5", "Fluent.Ribbon\Fluent.Ribbon.NET 4.5.csproj", "{4C92FCF4-3561-499F-BC5B-F2F089863047}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{B3EE3E07-9FD5-4282-9743-AC457EB45BBA}" - ProjectSection(SolutionItems) = preProject - Changelog.md = Changelog.md - Shared\GlobalAssemblyInfo.cs = Shared\GlobalAssemblyInfo.cs - License.txt = License.txt - ReleaseNotes.md = ReleaseNotes.md - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent dotNET 4.0", "Fluent\Fluent dotNET 4.0.csproj", "{281095D8-D8B3-4A7F-8896-646483FB685C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent.Ribbon.NET 4.0", "Fluent.Ribbon\Fluent.Ribbon.NET 4.0.csproj", "{281095D8-D8B3-4A7F-8896-646483FB685C}" ProjectSection(ProjectDependencies) = postProject {4C92FCF4-3561-499F-BC5B-F2F089863047} = {4C92FCF4-3561-499F-BC5B-F2F089863047} EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentTest dotNET 4.0", "FluentTest\FluentTest dotNET 4.0.csproj", "{2A893D50-BBC4-4482-ADAA-D52B517E8632}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fluent.Ribbon.Showcase.NET 4.0", "Fluent.Ribbon.Showcase\Fluent.Ribbon.Showcase.NET 4.0.csproj", "{2A893D50-BBC4-4482-ADAA-D52B517E8632}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{1318E3D3-5156-45FE-9828-464A2D0235E0}" ProjectSection(SolutionItems) = preProject @@ -30,12 +22,20 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{CDBFA905-C104-421D-9502-C4DF042EC048}" ProjectSection(SolutionItems) = preProject appveyor.yml = appveyor.yml - Build.cmd = Build.cmd - BuildForPublish.cmd = BuildForPublish.cmd + Build.ps1 = Build.ps1 Fluent.Ribbon.msbuild = Fluent.Ribbon.msbuild Fluent.Ribbon.nuspec = Fluent.Ribbon.nuspec EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C6ADD536-3DB2-4418-AED6-98AB991D1B77}" + ProjectSection(SolutionItems) = preProject + Changelog.md = Changelog.md + Shared\GlobalAssemblyInfo.cs = Shared\GlobalAssemblyInfo.cs + License.txt = License.txt + README.md = README.md + ReleaseNotes.md = ReleaseNotes.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/Fluent.Ribbon.sln.DotSettings b/Fluent.Ribbon.sln.DotSettings index 7415f3df4..76edc43ef 100644 --- a/Fluent.Ribbon.sln.DotSettings +++ b/Fluent.Ribbon.sln.DotSettings @@ -7,6 +7,7 @@ ALWAYS_USE False False + True True True True diff --git a/Fluent/Adorners/KeyTipAdorner.cs b/Fluent.Ribbon/Adorners/KeyTipAdorner.cs similarity index 71% rename from Fluent/Adorners/KeyTipAdorner.cs rename to Fluent.Ribbon/Adorners/KeyTipAdorner.cs index 365f72f48..c19685423 100644 --- a/Fluent/Adorners/KeyTipAdorner.cs +++ b/Fluent.Ribbon/Adorners/KeyTipAdorner.cs @@ -1,1111 +1,889 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Threading; - -namespace Fluent -{ - using System.Diagnostics; - - /// - /// Represents adorner for KeyTips. - /// KeyTipAdorners is chained to produce one from another. - /// Detaching root adorner couses detaching all adorners in the chain - /// - internal class KeyTipAdorner : Adorner - { - #region Events - - /// - /// This event is occured when adorner is - /// detached and is not able to be attached again - /// - public event EventHandler Terminated; - - #endregion - - #region Fields - - // KeyTips that have been - // found on this element - private readonly List keyTips = new List(); - private readonly List associatedElements = new List(); - private readonly FrameworkElement oneOfAssociatedElements; - private readonly Point[] keyTipPositions; - - // Parent adorner - private readonly KeyTipAdorner parentAdorner; - KeyTipAdorner childAdorner; - - // Focused element - private IInputElement focusedElement; - - private readonly Visibility[] backupedVisibilities; - private readonly UIElement keyTipElementContainer; - - // Is this adorner attached to the adorned element? - private bool attached; - private HwndSource attachedHwndSource; - - // Current entered chars - string enteredKeys = ""; - - // Designate that this adorner is terminated - private bool terminated; - - private DispatcherTimer timerFocusTracking; - - private AdornerLayer adornerLayer; - - #endregion - - #region Properties - - /// - /// Determines whether at least one on the adorners in the chain is alive - /// - public bool IsAdornerChainAlive - { - get { return this.attached || (this.childAdorner != null && this.childAdorner.IsAdornerChainAlive); } - } - - public bool AreAnyKeyTipsVisible - { - get { return this.keyTips.Any(x => x.IsVisible) || (this.childAdorner != null && this.childAdorner.AreAnyKeyTipsVisible); } - } - - public KeyTipAdorner ActiveKeyTipAdorner - { - get - { - return this.childAdorner != null && this.childAdorner.IsAdornerChainAlive - ? this.childAdorner.ActiveKeyTipAdorner - : this; - } - } - - #endregion - - #region Intialization - - /// - /// Construcotor - /// - /// - /// Parent adorner or null - /// The element which is container for elements - public KeyTipAdorner(UIElement adornedElement, UIElement keyTipElementContainer, KeyTipAdorner parentAdorner) - : base(adornedElement) - { - this.parentAdorner = parentAdorner; - - this.keyTipElementContainer = keyTipElementContainer; - - // Try to find supported elements - this.FindKeyTips(this.keyTipElementContainer, false); - this.oneOfAssociatedElements = (FrameworkElement)(this.associatedElements.Count != 0 - ? this.associatedElements[0] - : adornedElement // Maybe here is bug, coz we need keytipped item here... - ); - - this.keyTipPositions = new Point[this.keyTips.Count]; - this.backupedVisibilities = new Visibility[this.keyTips.Count]; - } - - // Find key tips on the given element - private void FindKeyTips(UIElement element, bool hide) - { - this.Log("FindKeyTips"); - - var children = LogicalTreeHelper.GetChildren(element); - foreach (var item in children) - { - var child = item as UIElement; - - if (child == null - || child.Visibility != Visibility.Visible) - { - continue; - } - - var groupBox = child as RibbonGroupBox; - - var keys = KeyTip.GetKeys(child); - if (keys != null) - { - // Gotcha! - var keyTip = new KeyTip - { - Content = keys, - Visibility = hide - ? Visibility.Collapsed - : Visibility.Visible - }; - - // Add to list & visual - // children collections - this.keyTips.Add(keyTip); - this.AddVisualChild(keyTip); - this.associatedElements.Add(child); - - if (groupBox != null) - { - if (groupBox.State == RibbonGroupBoxState.Collapsed) - { - keyTip.Visibility = Visibility.Visible; - this.FindKeyTips(child, true); - continue; - } - else - { - keyTip.Visibility = Visibility.Collapsed; - } - } - else - { - // Bind IsEnabled property - var binding = new Binding("IsEnabled") - { - Source = child, - Mode = BindingMode.OneWay - }; - keyTip.SetBinding(IsEnabledProperty, binding); - continue; - } - } - - if (groupBox != null && - groupBox.State == RibbonGroupBoxState.Collapsed) - { - this.FindKeyTips(child, true); - } - else - { - this.FindKeyTips(child, hide); - } - } - } - - #endregion - - #region Attach & Detach - - /// - /// Attaches this adorner to the adorned element - /// - public void Attach() - { - if (this.attached) - { - return; - } - - this.oneOfAssociatedElements.UpdateLayout(); - - this.Log("Attach begin {0}", this.Visibility); - - if (!this.oneOfAssociatedElements.IsLoaded) - { - // Delay attaching - this.Log("Delaying attach"); - this.oneOfAssociatedElements.Loaded += this.OnDelayAttach; - return; - } - - this.adornerLayer = GetAdornerLayer(this.oneOfAssociatedElements); - - if (this.adornerLayer == null) - { - this.Log("No adorner layer found"); - return; - } - - // Focus current adorned element - // Keyboard.Focus(adornedElement); - this.focusedElement = Keyboard.FocusedElement; - - if (this.focusedElement != null) - { - this.Log("Focus Attached to {0}", this.focusedElement); - this.focusedElement.LostKeyboardFocus += this.OnFocusLost; - this.focusedElement.PreviewKeyDown += this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput += this.OnFocusedElementPreviewTextInput; - } - else - { - this.Log("[!] Focus Setup Failed"); - } - - GetTopLevelElement(this.oneOfAssociatedElements).PreviewMouseDown += this.OnInputActionOccured; - - // Clears previous user input - this.enteredKeys = ""; - this.FilterKeyTips(); - - // Show this adorner - this.adornerLayer.Add(this); - - // Hookup window activation - this.attachedHwndSource = ((HwndSource)PresentationSource.FromVisual(this.oneOfAssociatedElements)); - if (this.attachedHwndSource != null) - { - this.attachedHwndSource.AddHook(this.WindowProc); - } - - // Start timer to track focus changing - if (this.timerFocusTracking == null) - { - this.timerFocusTracking = new DispatcherTimer(DispatcherPriority.ApplicationIdle, Dispatcher.CurrentDispatcher) - { - Interval = TimeSpan.FromMilliseconds(50) - }; - this.timerFocusTracking.Tick += this.OnTimerFocusTrackingTick; - } - - this.timerFocusTracking.Start(); - - this.attached = true; - - this.Log("Attach end"); - } - - private void OnTimerFocusTrackingTick(object sender, EventArgs e) - { - if (this.focusedElement == Keyboard.FocusedElement) - { - return; - } - - this.Log("Focus is changed, but focus lost is not occured"); - - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus -= this.OnFocusLost; - this.focusedElement.PreviewKeyDown -= this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput -= this.OnFocusedElementPreviewTextInput; - } - - this.focusedElement = Keyboard.FocusedElement; - - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus += this.OnFocusLost; - this.focusedElement.PreviewKeyDown += this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput += this.OnFocusedElementPreviewTextInput; - } - } - - // Window's messages hook up - private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - // Check whether window is deactivated (wParam == 0) - if ((msg == 6) && (wParam == IntPtr.Zero) && (this.attached)) - { - this.Log("The host window is deactivated, keytips will be terminated"); - this.Terminate(); - } - - return IntPtr.Zero; - } - - private void OnDelayAttach(object sender, EventArgs args) - { - this.Log("Delay attach (control loaded)"); - this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach; - this.Attach(); - } - - /// - /// Detaches this adorner from the adorned element - /// - public void Detach() - { - if (this.childAdorner != null) - { - this.childAdorner.Detach(); - } - - if (!this.attached) - { - return; - } - - this.Log("Detach Begin"); - - // Remove window hookup - if ((this.attachedHwndSource != null) && (!this.attachedHwndSource.IsDisposed)) - { - // Crashes in a few time if invoke immediately ??? - this.AdornedElement.Dispatcher.BeginInvoke((System.Threading.ThreadStart)(() => this.attachedHwndSource.RemoveHook(this.WindowProc))); - } - - // Maybe adorner awaiting attaching, cancel it - this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach; - - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus -= this.OnFocusLost; - this.focusedElement.PreviewKeyDown -= this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput -= this.OnFocusedElementPreviewTextInput; - this.focusedElement = null; - } - - GetTopLevelElement(this.oneOfAssociatedElements).PreviewMouseDown -= this.OnInputActionOccured; - - // Show this adorner - this.adornerLayer.Remove(this); - // Clears previous user input - this.enteredKeys = ""; - this.attached = false; - - // Stop timer to track focus changing - this.timerFocusTracking.Stop(); - - this.Log("Detach End"); - } - - #endregion - - #region Termination - - /// - /// Terminate whole key tip's adorner chain - /// - public void Terminate() - { - if (this.terminated) - { - return; - } - - this.terminated = true; - - this.Detach(); - - if (this.parentAdorner != null) - { - this.parentAdorner.Terminate(); - } - - if (this.childAdorner != null) - { - this.childAdorner.Terminate(); - } - - if (this.Terminated != null) - { - this.Terminated(this, EventArgs.Empty); - } - - this.Log("Termination"); - } - - #endregion - - #region Event Handlers - - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - private void OnPreviewKeyDown(object sender, KeyEventArgs e) - { - this.Log("Key Down {0} ({1})", e.Key, e.OriginalSource); - - if (e.IsRepeat - || this.Visibility == Visibility.Hidden) - { - return; - } - - if ((!(this.AdornedElement is ContextMenu)) && - ((e.Key == Key.Left) || (e.Key == Key.Right) || (e.Key == Key.Up) || (e.Key == Key.Down) || - (e.Key == Key.Enter) || (e.Key == Key.Tab))) - { - this.Visibility = Visibility.Hidden; - } - else if (e.Key == Key.Escape) - { - this.Back(); - e.Handled = true; - } - } - - private void OnFocusedElementPreviewTextInput(object sender, TextCompositionEventArgs e) - { - var keyToSearch = this.enteredKeys + e.Text; - - if (this.IsElementsStartWith(keyToSearch)) - { - this.enteredKeys += e.Text; - - var element = this.TryGetElement(this.enteredKeys); - - if (element != null) - { - this.Forward(element); - } - else - { - this.FilterKeyTips(); - } - - e.Handled = true; - } - else - { - System.Media.SystemSounds.Beep.Play(); - } - } - - private void OnInputActionOccured(object sender, RoutedEventArgs e) - { - if (!this.attached) - { - return; - } - - this.Log("Input Action, Keystips will be terminated"); - this.Terminate(); - } - - private void OnFocusLost(object sender, RoutedEventArgs e) - { - if (!this.attached) - { - return; - } - - this.Log("Focus Lost"); - - var previousFocusedElementElement = this.focusedElement; - this.focusedElement.LostKeyboardFocus -= this.OnFocusLost; - this.focusedElement.PreviewKeyDown -= this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput -= this.OnFocusedElementPreviewTextInput; - this.focusedElement = Keyboard.FocusedElement; - - if (this.focusedElement != null) - { - this.Log("Focus Changed from {0} to {1}", previousFocusedElementElement, this.focusedElement); - this.focusedElement.LostKeyboardFocus += this.OnFocusLost; - this.focusedElement.PreviewKeyDown += this.OnPreviewKeyDown; - this.focusedElement.PreviewTextInput += this.OnFocusedElementPreviewTextInput; - } - else - { - this.Log("Focus Not Restored"); - } - } - - #endregion - - #region Static Methods - - private static AdornerLayer GetAdornerLayer(UIElement element) - { - var current = element; - - while (true) - { - if (current == null) return null; - - var parent = (UIElement)VisualTreeHelper.GetParent(current) - ?? (UIElement)LogicalTreeHelper.GetParent(current); - - current = parent; - - if (current is AdornerDecorator) - { - return AdornerLayer.GetAdornerLayer((UIElement)VisualTreeHelper.GetChild(current, 0)); - } - } - } - - private static UIElement GetTopLevelElement(UIElement element) - { - var current = element; - - while (true) - { - current = (VisualTreeHelper.GetParent(element)) as UIElement; - - if (current == null) - { - return element; - } - - element = current; - } - } - - #endregion - - #region Methods - - // Back to the previous adorner - public void Back() - { - var control = this.keyTipElementContainer as IKeyTipedControl; - if (control != null) - { - control.OnKeyTipBack(); - } - - if (this.parentAdorner != null) - { - this.Log("Back"); - this.Detach(); - this.parentAdorner.Attach(); - } - else - { - this.Terminate(); - } - } - - /// - /// Forwards to the elements with the given keys - /// - /// Keys - /// If true the element will be clicked - /// If the element will be found the function will return true - public bool Forward(string keys, bool click) - { - this.Log("Trying to forward {0}", keys); - - var element = this.TryGetElement(keys); - if (element == null) - { - return false; - } - - this.Forward(element, click); - return true; - } - - // Forward to the next element - private void Forward(UIElement element) { - this.Forward(element, true); } - - // Forward to the next element - private void Forward(UIElement element, bool click) - { - this.Log("Forwarding"); - - this.Detach(); - - if (click) - { - //element.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, null)); - var control = element as IKeyTipedControl; - if (control != null) - { - control.OnKeyTipPressed(); - } - } - - var children = LogicalTreeHelper.GetChildren(element) - .OfType() - .ToArray(); - - if (children.Length == 0) - { - this.Terminate(); - return; - } - - this.childAdorner = ReferenceEquals(GetTopLevelElement(children[0]), GetTopLevelElement(element)) == false - ? new KeyTipAdorner(children[0], element, this) - : new KeyTipAdorner(element, element, this); - - // Stop if no further KeyTips can be displayed. - if (!this.childAdorner.keyTips.Any()) - { - this.Terminate(); - return; - } - - this.childAdorner.Attach(); - } - - /// - /// Gets element keytipped by keys - /// - /// - /// Element - private UIElement TryGetElement(string keys) - { - for (var i = 0; i < this.keyTips.Count; i++) - { - if (!this.keyTips[i].IsEnabled - || - this.keyTips[i].Visibility != Visibility.Visible) - { - continue; - } - - var content = (string)this.keyTips[i].Content; - - if (keys.Equals(content, StringComparison.CurrentCultureIgnoreCase)) - { - return this.associatedElements[i]; - } - } - - return null; - } - - /// - /// Is one of the elements starts with the given chars - /// - /// - /// - private bool IsElementsStartWith(string keys) - { - foreach (var keyTip in this.keyTips.Where(x => x.IsEnabled)) - { - var content = (string)keyTip.Content; - - if (content.StartsWith(keys, StringComparison.CurrentCultureIgnoreCase)) - { - return true; - } - } - - return false; - } - - // Hide / unhide keytips relative matching to entered keys - private void FilterKeyTips() - { - this.Log("FilterKeyTips"); - - // Backup current visibility of key tips - for (var i = 0; i < this.backupedVisibilities.Length; i++) - { - this.backupedVisibilities[i] = this.keyTips[i].Visibility; - } - - // Hide / unhide keytips relative matching to entered keys - for (var i = 0; i < this.keyTips.Count; i++) - { - var content = (string)this.keyTips[i].Content; - - if (string.IsNullOrEmpty(this.enteredKeys)) - { - this.keyTips[i].Visibility = this.backupedVisibilities[i]; - } - else - { - this.keyTips[i].Visibility = content.StartsWith(this.enteredKeys, StringComparison.CurrentCultureIgnoreCase) - ? this.backupedVisibilities[i] - : Visibility.Collapsed; - } - } - - this.Log("Filtered key tips: {0}", this.keyTips.Count(x => x.Visibility == Visibility.Visible)); - } - - #endregion - - #region Layout & Visual Children - - /// - /// Positions child elements and determines - /// a size for the control - /// - /// The final area within the parent - /// that this element should use to arrange - /// itself and its children - /// The actual size used - protected override Size ArrangeOverride(Size finalSize) - { - this.Log("ArrangeOverride"); - - for (var i = 0; i < this.keyTips.Count; i++) - { - this.keyTips[i].Arrange(new Rect(this.keyTipPositions[i], this.keyTips[i].DesiredSize)); - } - - return finalSize; - } - - /// - /// Measures KeyTips - /// - /// The available size that this element can give to child elements. - /// The size that the groups container determines it needs during - /// layout, based on its calculations of child element sizes. - /// - protected override Size MeasureOverride(Size constraint) - { - this.Log("MeasureOverride"); - - var infinitySize = new Size(double.PositiveInfinity, double.PositiveInfinity); - foreach (var tip in this.keyTips) - { - tip.Measure(infinitySize); - } - - this.UpdateKeyTipPositions(); - - var result = new Size(0, 0); - for (var i = 0; i < this.keyTips.Count; i++) - { - var cornerX = this.keyTips[i].DesiredSize.Width + this.keyTipPositions[i].X; - var cornerY = this.keyTips[i].DesiredSize.Height + this.keyTipPositions[i].Y; - - if (cornerX > result.Width) - { - result.Width = cornerX; - } - - if (cornerY > result.Height) - { - result.Height = cornerY; - } - } - - return result; - } - - /// - /// Gets parent RibbonGroupBox or null - /// - /// - /// - private static RibbonGroupBox GetGroupBox(DependencyObject element) - { - if (element == null) - { - return null; - } - - var groupBox = element as RibbonGroupBox; - if (groupBox != null) - { - return groupBox; - } - - var parent = VisualTreeHelper.GetParent(element); - return GetGroupBox(parent); - } - - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - private void UpdateKeyTipPositions() - { - this.Log("UpdateKeyTipPositions"); - - if (this.keyTips.Count == 0) - { - return; - } - - double[] rows = null; - var groupBox = GetGroupBox(this.oneOfAssociatedElements); - if (groupBox != null) - { - var panel = groupBox.GetPanel(); - if (panel != null) - { - var height = groupBox.GetLayoutRoot().DesiredSize.Height; - rows = new[] - { - groupBox.GetLayoutRoot().TranslatePoint(new Point(0, 0), this.AdornedElement).Y, - groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height / 2.0), this.AdornedElement).Y, - groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height), this.AdornedElement).Y, - groupBox.GetLayoutRoot().TranslatePoint(new Point(0, height + 1), this.AdornedElement).Y - }; - } - } - - for (var i = 0; i < this.keyTips.Count; i++) - { - // Skip invisible keytips - if (this.keyTips[i].Visibility != Visibility.Visible) - { - continue; - } - - // Update KeyTip Visibility - var associatedElementIsVisible = this.associatedElements[i].IsVisible; - var associatedElementInVisualTree = VisualTreeHelper.GetParent(this.associatedElements[i]) != null; - this.keyTips[i].Visibility = associatedElementIsVisible && associatedElementInVisualTree ? Visibility.Visible : Visibility.Collapsed; - - if (!KeyTip.GetAutoPlacement(this.associatedElements[i])) - { - #region Custom Placement - - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].RenderSize; - - double x = 0, y = 0; - var margin = KeyTip.GetMargin(this.associatedElements[i]); - - switch (KeyTip.GetHorizontalAlignment(this.associatedElements[i])) - { - case HorizontalAlignment.Left: - x = margin.Left; - break; - case HorizontalAlignment.Right: - x = elementSize.Width - keyTipSize.Width - margin.Right; - break; - case HorizontalAlignment.Center: - case HorizontalAlignment.Stretch: - x = elementSize.Width / 2.0 - keyTipSize.Width / 2.0 + margin.Left; - break; - } - - switch (KeyTip.GetVerticalAlignment(this.associatedElements[i])) - { - case VerticalAlignment.Top: - y = margin.Top; - break; - case VerticalAlignment.Bottom: - y = elementSize.Height - keyTipSize.Height - margin.Bottom; - break; - case VerticalAlignment.Center: - case VerticalAlignment.Stretch: - y = elementSize.Height / 2.0 - keyTipSize.Height / 2.0 + margin.Top; - break; - } - - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point(x, y), this.AdornedElement); - - #endregion - } - else if (((FrameworkElement)this.associatedElements[i]).Name == "PART_DialogLauncherButton") - { - // Dialog Launcher Button Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].RenderSize; - if (rows == null) - { - continue; - } - - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( - elementSize.Width / 2.0 - keyTipSize.Width / 2.0, - 0), this.AdornedElement); - this.keyTipPositions[i].Y = rows[3]; - } - else if ((this.associatedElements[i] is InRibbonGallery && !((InRibbonGallery)this.associatedElements[i]).IsCollapsed)) - { - // InRibbonGallery Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].RenderSize; - if (rows == null) - { - continue; - } - - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( - elementSize.Width - keyTipSize.Width / 2.0, - 0), this.AdornedElement); - this.keyTipPositions[i].Y = rows[2] - keyTipSize.Height / 2; - } - else if ((this.associatedElements[i] is RibbonTabItem) || (this.associatedElements[i] is Backstage)) - { - // Ribbon Tab Item Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].RenderSize; - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( - elementSize.Width / 2.0 - keyTipSize.Width / 2.0, - elementSize.Height - keyTipSize.Height / 2.0), this.AdornedElement); - } - else if (this.associatedElements[i] is RibbonGroupBox) - { - // Ribbon Group Box Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].DesiredSize; - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( - elementSize.Width / 2.0 - keyTipSize.Width / 2.0, - elementSize.Height + 1), this.AdornedElement); - } - else if (IsWithinQuickAccessToolbar(this.associatedElements[i])) - { - var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.associatedElements[i].DesiredSize.Width / 2.0 - this.keyTips[i].DesiredSize.Width / 2.0, this.associatedElements[i].DesiredSize.Height - this.keyTips[i].DesiredSize.Height / 2.0), this.AdornedElement); - this.keyTipPositions[i] = translatedPoint; - } - else if (this.associatedElements[i] is MenuItem) - { - // MenuItem Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].DesiredSize; - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint( - new Point( - elementSize.Height / 2.0 + 2, - elementSize.Height / 2.0 + 2), this.AdornedElement); - } - else if (this.associatedElements[i] is BackstageTabItem) - { - // BackstageButton Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].DesiredSize; - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint( - new Point( - 5, - elementSize.Height / 2.0 - keyTipSize.Height), this.AdornedElement); - } - else if (((FrameworkElement)this.associatedElements[i]).Parent is BackstageTabControl) - { - // Backstage Items Exclusive Placement - var keyTipSize = this.keyTips[i].DesiredSize; - var elementSize = this.associatedElements[i].DesiredSize; - this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint( - new Point( - 20, - elementSize.Height / 2.0 - keyTipSize.Height), this.AdornedElement); - } - else - { - if ((RibbonProperties.GetSize(this.associatedElements[i]) != RibbonControlSize.Large) - || (this.associatedElements[i] is Spinner) - || (this.associatedElements[i] is ComboBox) - || (this.associatedElements[i] is TextBox) - || (this.associatedElements[i] is CheckBox)) - { - var withinRibbonToolbar = IsWithinRibbonToolbarInTwoLine(this.associatedElements[i]); - var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.keyTips[i].DesiredSize.Width / 2.0, this.keyTips[i].DesiredSize.Height / 2.0), this.AdornedElement); - - // Snapping to rows if it present - if (rows != null) - { - var index = 0; - var mindistance = Math.Abs(rows[0] - translatedPoint.Y); - for (var j = 1; j < rows.Length; j++) - { - if (withinRibbonToolbar && j == 1) - { - continue; - } - - var distance = Math.Abs(rows[j] - translatedPoint.Y); - if (distance < mindistance) - { - mindistance = distance; - index = j; - } - } - - translatedPoint.Y = rows[index] - this.keyTips[i].DesiredSize.Height / 2.0; - } - - this.keyTipPositions[i] = translatedPoint; - } - else - { - var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.associatedElements[i].DesiredSize.Width / 2.0 - this.keyTips[i].DesiredSize.Width / 2.0, this.associatedElements[i].DesiredSize.Height - 8), this.AdornedElement); - if (rows != null) - { - translatedPoint.Y = rows[2] - this.keyTips[i].DesiredSize.Height / 2.0; - } - - this.keyTipPositions[i] = translatedPoint; - } - } - } - } - - // Determines whether the element is children to RibbonToolBar - private static bool IsWithinRibbonToolbarInTwoLine(DependencyObject element) - { - var parent = LogicalTreeHelper.GetParent(element) as UIElement; - var ribbonToolBar = parent as RibbonToolBar; - if (ribbonToolBar != null) - { - var definition = ribbonToolBar.GetCurrentLayoutDefinition(); - if (definition == null) - { - return false; - } - - if (definition.RowCount == 2 || definition.Rows.Count == 2) - { - return true; - } - - return false; - } - - if (parent == null) - { - return false; - } - - return IsWithinRibbonToolbarInTwoLine(parent); - } - - // Determines whether the element is children to quick access toolbar - private static bool IsWithinQuickAccessToolbar(DependencyObject element) - { - var parent = LogicalTreeHelper.GetParent(element) as UIElement; - if (parent is QuickAccessToolBar) - { - return true; - } - - if (parent == null) - { - return false; - } - - return IsWithinQuickAccessToolbar(parent); - } - - /// - /// Gets visual children count - /// - protected override int VisualChildrenCount - { - get - { - return this.keyTips.Count; - } - } - - /// - /// Returns a child at the specified index from a collection of child elements - /// - /// The zero-based index of the requested child element in the collection - /// The requested child element - protected override Visual GetVisualChild(int index) - { - return this.keyTips[index]; - } - - #endregion - - #region Logging - - [SuppressMessage("Microsoft.Performance", "CA1822")] - [SuppressMessage("Microsoft.Performance", "CA1801")] - [Conditional("DEBUG")] - private void Log(string format, params object[] args) - { - var name = this.AdornedElement.GetType().Name; - - var headeredControl = this.AdornedElement as IHeaderedControl; - if (headeredControl != null) - { - name += string.Format(" ({0})", headeredControl.Header); - } - - Debug.WriteLine("[" + name + "] " + string.Format(format, args), "KeyTipAdorner"); - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Data; + using System.Windows.Documents; + using System.Windows.Media; + using Fluent.Internal; + + /// + /// Represents adorner for KeyTips. + /// KeyTipAdorners is chained to produce one from another. + /// Detaching root adorner couses detaching all adorners in the chain + /// + internal class KeyTipAdorner : Adorner + { + #region Events + + /// + /// This event is occured when adorner is + /// detached and is not able to be attached again + /// + public event EventHandler Terminated; + + #endregion + + #region Fields + + // KeyTips that have been + // found on this element + private readonly List keyTips = new List(); + private readonly List associatedElements = new List(); + private readonly FrameworkElement oneOfAssociatedElements; + private readonly Point[] keyTipPositions; + + // Parent adorner + private readonly KeyTipAdorner parentAdorner; + KeyTipAdorner childAdorner; + + private readonly Visibility[] backupedVisibilities; + private readonly UIElement keyTipElementContainer; + + // Is this adorner attached to the adorned element? + private bool attached; + + // Designate that this adorner is terminated + private bool terminated; + + private AdornerLayer adornerLayer; + + #endregion + + #region Properties + + /// + /// Determines whether at least one on the adorners in the chain is alive + /// + public bool IsAdornerChainAlive + { + get { return this.attached || (this.childAdorner != null && this.childAdorner.IsAdornerChainAlive); } + } + + public bool AreAnyKeyTipsVisible + { + get { return this.keyTips.Any(x => x.IsVisible) || (this.childAdorner != null && this.childAdorner.AreAnyKeyTipsVisible); } + } + + public KeyTipAdorner ActiveKeyTipAdorner + { + get + { + return this.childAdorner != null && this.childAdorner.IsAdornerChainAlive + ? this.childAdorner.ActiveKeyTipAdorner + : this; + } + } + + #endregion + + #region Intialization + + /// + /// Construcotor + /// + /// + /// Parent adorner or null + /// The element which is container for elements + public KeyTipAdorner(UIElement adornedElement, UIElement keyTipElementContainer, KeyTipAdorner parentAdorner) + : base(adornedElement) + { + this.parentAdorner = parentAdorner; + + this.keyTipElementContainer = keyTipElementContainer; + + // Try to find supported elements + this.FindKeyTips(this.keyTipElementContainer, false); + this.oneOfAssociatedElements = (FrameworkElement)(this.associatedElements.Count != 0 + ? this.associatedElements[0] + : adornedElement // Maybe here is bug, coz we need keytipped item here... + ); + + this.keyTipPositions = new Point[this.keyTips.Count]; + this.backupedVisibilities = new Visibility[this.keyTips.Count]; + } + + // Find key tips on the given element + private void FindKeyTips(UIElement element, bool hide) + { + this.Log("FindKeyTips"); + + var children = GetVisibleChildren(element); + + foreach (var child in children) + { + var groupBox = child as RibbonGroupBox; + + var keys = KeyTip.GetKeys(child); + if (keys != null) + { + // Gotcha! + var keyTip = new KeyTip + { + Content = keys, + Visibility = hide + ? Visibility.Collapsed + : Visibility.Visible + }; + + // Add to list & visual + // children collections + this.keyTips.Add(keyTip); + this.AddVisualChild(keyTip); + this.associatedElements.Add(child); + + if (groupBox != null) + { + if (groupBox.State == RibbonGroupBoxState.Collapsed) + { + keyTip.Visibility = Visibility.Visible; + this.FindKeyTips(child, true); + continue; + } + else + { + keyTip.Visibility = Visibility.Collapsed; + } + } + else + { + // Bind IsEnabled property + var binding = new Binding("IsEnabled") + { + Source = child, + Mode = BindingMode.OneWay + }; + keyTip.SetBinding(IsEnabledProperty, binding); + continue; + } + } + + if (groupBox != null && + groupBox.State == RibbonGroupBoxState.Collapsed) + { + this.FindKeyTips(child, true); + } + else + { + this.FindKeyTips(child, hide); + } + } + } + + private static UIElement[] GetVisibleChildren(UIElement element) + { + var logicalChildren = LogicalTreeHelper.GetChildren(element) + .OfType(); + + var children = logicalChildren; + + // Always using the visual tree is very expensive, so we only search through it when you got specific control types. + // Using the visual tree here, in addition to the logical, partially fixes #244. + if (element is ContentPresenter + || element is ContentControl) + { + children = children + .Concat(UIHelper.GetVisualChildren(element)) + .OfType(); + } + + return children + .Where(x => x.Visibility == Visibility.Visible) + .Distinct() + .ToArray(); + } + + #endregion + + #region Attach & Detach + + /// + /// Attaches this adorner to the adorned element + /// + public void Attach() + { + if (this.attached) + { + return; + } + + this.oneOfAssociatedElements.UpdateLayout(); + + this.Log("Attach begin {0}", this.Visibility); + + if (this.oneOfAssociatedElements.IsLoaded == false) + { + // Delay attaching + this.Log("Delaying attach"); + this.oneOfAssociatedElements.Loaded += this.OnDelayAttach; + return; + } + + this.adornerLayer = GetAdornerLayer(this.oneOfAssociatedElements); + + if (this.adornerLayer == null) + { + this.Log("No adorner layer found"); + return; + } + + this.FilterKeyTips(string.Empty); + + // Show this adorner + this.adornerLayer.Add(this); + + this.attached = true; + + this.Log("Attach end"); + } + + private void OnDelayAttach(object sender, EventArgs args) + { + this.Log("Delay attach (control loaded)"); + this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach; + this.Attach(); + } + + /// + /// Detaches this adorner from the adorned element + /// + public void Detach() + { + if (this.childAdorner != null) + { + this.childAdorner.Detach(); + } + + if (!this.attached) + { + return; + } + + this.Log("Detach Begin"); + + // Maybe adorner awaiting attaching, cancel it + this.oneOfAssociatedElements.Loaded -= this.OnDelayAttach; + + // Show this adorner + this.adornerLayer.Remove(this); + + this.attached = false; + + this.Log("Detach End"); + } + + #endregion + + #region Termination + + /// + /// Terminate whole key tip's adorner chain + /// + public void Terminate() + { + if (this.terminated) + { + return; + } + + this.terminated = true; + + this.Detach(); + + this.parentAdorner?.Terminate(); + + this.childAdorner?.Terminate(); + + this.Terminated?.Invoke(this, EventArgs.Empty); + + this.Log("Termination"); + } + + #endregion + + #region Static Methods + + private static AdornerLayer GetAdornerLayer(UIElement element) + { + var current = element; + + while (true) + { + if (current == null) return null; + + var parent = (UIElement)VisualTreeHelper.GetParent(current) + ?? (UIElement)LogicalTreeHelper.GetParent(current); + + current = parent; + + if (current is AdornerDecorator) + { + return AdornerLayer.GetAdornerLayer((UIElement)VisualTreeHelper.GetChild(current, 0)); + } + } + } + + private static UIElement GetTopLevelElement(UIElement element) + { + var current = element; + + while (true) + { + current = (VisualTreeHelper.GetParent(element)) as UIElement; + + if (current == null) + { + return element; + } + + element = current; + } + } + + #endregion + + #region Methods + + // Back to the previous adorner + public void Back() + { + var control = this.keyTipElementContainer as IKeyTipedControl; + control?.OnKeyTipBack(); + + if (this.parentAdorner != null) + { + this.Log("Back"); + this.Detach(); + this.parentAdorner.Attach(); + } + else + { + this.Terminate(); + } + } + + /// + /// Forwards to the elements with the given keys + /// + /// Keys + /// If true the element will be clicked + /// If the element will be found the function will return true + public bool Forward(string keys, bool click) + { + this.Log("Trying to forward {0}", keys); + + var element = this.TryGetElement(keys); + if (element == null) + { + return false; + } + + this.Forward(element, click); + return true; + } + + // Forward to the next element + private void Forward(UIElement element, bool click) + { + this.Log("Forwarding to {0}", element); + + this.Detach(); + + if (click) + { + //element.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, null)); + var control = element as IKeyTipedControl; + if (control != null) + { + control.OnKeyTipPressed(); + } + } + + var children = GetVisibleChildren(element); + + if (children.Length == 0) + { + this.Terminate(); + return; + } + + this.childAdorner = ReferenceEquals(GetTopLevelElement(children[0]), GetTopLevelElement(element)) == false + ? new KeyTipAdorner(children[0], element, this) + : new KeyTipAdorner(element, element, this); + + // Stop if no further KeyTips can be displayed. + if (this.childAdorner.keyTips.Any() == false) + { + this.Terminate(); + return; + } + + this.childAdorner.Attach(); + } + + /// + /// Gets element keytipped by keys + /// + /// + /// Element + private UIElement TryGetElement(string keys) + { + for (var i = 0; i < this.keyTips.Count; i++) + { + if (!this.keyTips[i].IsEnabled + || + this.keyTips[i].Visibility != Visibility.Visible) + { + continue; + } + + var content = (string)this.keyTips[i].Content; + + if (keys.Equals(content, StringComparison.CurrentCultureIgnoreCase)) + { + return this.associatedElements[i]; + } + } + + return null; + } + + /// + /// Determines if an of the keytips contained in this adorner start with + /// + /// true if any keytip start with . Otherwise false. + public bool ContainsKeyTipStartingWith(string keys) + { + foreach (var keyTip in this.keyTips.Where(x => x.IsEnabled)) + { + var content = (string)keyTip.Content; + + if (content.StartsWith(keys, StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + } + + return false; + } + + // Hide / unhide keytips relative matching to entered keys + internal void FilterKeyTips(string keys) + { + this.Log("FilterKeyTips with {0}", keys); + + // Backup current visibility of key tips + for (var i = 0; i < this.backupedVisibilities.Length; i++) + { + this.backupedVisibilities[i] = this.keyTips[i].Visibility; + } + + // Hide / unhide keytips relative matching to entered keys + for (var i = 0; i < this.keyTips.Count; i++) + { + var content = (string)this.keyTips[i].Content; + + if (string.IsNullOrEmpty(keys)) + { + this.keyTips[i].Visibility = this.backupedVisibilities[i]; + } + else + { + this.keyTips[i].Visibility = content.StartsWith(keys, StringComparison.CurrentCultureIgnoreCase) + ? this.backupedVisibilities[i] + : Visibility.Collapsed; + } + } + + this.Log("Filtered key tips: {0}", this.keyTips.Count(x => x.Visibility == Visibility.Visible)); + } + + #endregion + + #region Layout & Visual Children + + /// + /// Positions child elements and determines + /// a size for the control + /// + /// The final area within the parent + /// that this element should use to arrange + /// itself and its children + /// The actual size used + protected override Size ArrangeOverride(Size finalSize) + { + this.Log("ArrangeOverride"); + + for (var i = 0; i < this.keyTips.Count; i++) + { + this.keyTips[i].Arrange(new Rect(this.keyTipPositions[i], this.keyTips[i].DesiredSize)); + } + + return finalSize; + } + + /// + /// Measures KeyTips + /// + /// The available size that this element can give to child elements. + /// The size that the groups container determines it needs during + /// layout, based on its calculations of child element sizes. + /// + protected override Size MeasureOverride(Size constraint) + { + this.Log("MeasureOverride"); + + var infinitySize = new Size(double.PositiveInfinity, double.PositiveInfinity); + foreach (var tip in this.keyTips) + { + tip.Measure(infinitySize); + } + + this.UpdateKeyTipPositions(); + + var result = new Size(0, 0); + for (var i = 0; i < this.keyTips.Count; i++) + { + var cornerX = this.keyTips[i].DesiredSize.Width + this.keyTipPositions[i].X; + var cornerY = this.keyTips[i].DesiredSize.Height + this.keyTipPositions[i].Y; + + if (cornerX > result.Width) + { + result.Width = cornerX; + } + + if (cornerY > result.Height) + { + result.Height = cornerY; + } + } + + return result; + } + + /// + /// Gets parent RibbonGroupBox or null + /// + /// + /// + private static RibbonGroupBox GetGroupBox(DependencyObject element) + { + if (element == null) + { + return null; + } + + var groupBox = element as RibbonGroupBox; + if (groupBox != null) + { + return groupBox; + } + + var parent = VisualTreeHelper.GetParent(element); + return GetGroupBox(parent); + } + + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + private void UpdateKeyTipPositions() + { + this.Log("UpdateKeyTipPositions"); + + if (this.keyTips.Count == 0) + { + return; + } + + double[] rows = null; + var groupBox = GetGroupBox(this.oneOfAssociatedElements); + if (groupBox != null) + { + var panel = groupBox.GetPanel(); + if (panel != null) + { + var height = groupBox.GetLayoutRoot().DesiredSize.Height; + rows = new[] + { + groupBox.GetLayoutRoot().TranslatePoint(new Point(0, 0), this.AdornedElement).Y, + groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height / 2.0), this.AdornedElement).Y, + groupBox.GetLayoutRoot().TranslatePoint(new Point(0, panel.DesiredSize.Height), this.AdornedElement).Y, + groupBox.GetLayoutRoot().TranslatePoint(new Point(0, height + 1), this.AdornedElement).Y + }; + } + } + + for (var i = 0; i < this.keyTips.Count; i++) + { + // Skip invisible keytips + if (this.keyTips[i].Visibility != Visibility.Visible) + { + continue; + } + + // Update KeyTip Visibility + var associatedElementIsVisible = this.associatedElements[i].IsVisible; + var associatedElementInVisualTree = VisualTreeHelper.GetParent(this.associatedElements[i]) != null; + this.keyTips[i].Visibility = associatedElementIsVisible && associatedElementInVisualTree ? Visibility.Visible : Visibility.Collapsed; + + if (!KeyTip.GetAutoPlacement(this.associatedElements[i])) + { + #region Custom Placement + + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].RenderSize; + + double x = 0, y = 0; + var margin = KeyTip.GetMargin(this.associatedElements[i]); + + switch (KeyTip.GetHorizontalAlignment(this.associatedElements[i])) + { + case HorizontalAlignment.Left: + x = margin.Left; + break; + case HorizontalAlignment.Right: + x = elementSize.Width - keyTipSize.Width - margin.Right; + break; + case HorizontalAlignment.Center: + case HorizontalAlignment.Stretch: + x = elementSize.Width / 2.0 - keyTipSize.Width / 2.0 + margin.Left; + break; + } + + switch (KeyTip.GetVerticalAlignment(this.associatedElements[i])) + { + case VerticalAlignment.Top: + y = margin.Top; + break; + case VerticalAlignment.Bottom: + y = elementSize.Height - keyTipSize.Height - margin.Bottom; + break; + case VerticalAlignment.Center: + case VerticalAlignment.Stretch: + y = elementSize.Height / 2.0 - keyTipSize.Height / 2.0 + margin.Top; + break; + } + + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point(x, y), this.AdornedElement); + + #endregion + } + else if (((FrameworkElement)this.associatedElements[i]).Name == "PART_DialogLauncherButton") + { + // Dialog Launcher Button Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].RenderSize; + if (rows == null) + { + continue; + } + + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( + elementSize.Width / 2.0 - keyTipSize.Width / 2.0, + 0), this.AdornedElement); + this.keyTipPositions[i].Y = rows[3]; + } + else if ((this.associatedElements[i] is InRibbonGallery && !((InRibbonGallery)this.associatedElements[i]).IsCollapsed)) + { + // InRibbonGallery Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].RenderSize; + if (rows == null) + { + continue; + } + + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( + elementSize.Width - keyTipSize.Width / 2.0, + 0), this.AdornedElement); + this.keyTipPositions[i].Y = rows[2] - keyTipSize.Height / 2; + } + else if ((this.associatedElements[i] is RibbonTabItem) || (this.associatedElements[i] is Backstage)) + { + // Ribbon Tab Item Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].RenderSize; + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( + elementSize.Width / 2.0 - keyTipSize.Width / 2.0, + elementSize.Height - keyTipSize.Height / 2.0), this.AdornedElement); + } + else if (this.associatedElements[i] is RibbonGroupBox) + { + // Ribbon Group Box Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].DesiredSize; + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(new Point( + elementSize.Width / 2.0 - keyTipSize.Width / 2.0, + elementSize.Height + 1), this.AdornedElement); + } + else if (IsWithinQuickAccessToolbar(this.associatedElements[i])) + { + var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.associatedElements[i].DesiredSize.Width / 2.0 - this.keyTips[i].DesiredSize.Width / 2.0, this.associatedElements[i].DesiredSize.Height - this.keyTips[i].DesiredSize.Height / 2.0), this.AdornedElement); + this.keyTipPositions[i] = translatedPoint; + } + else if (this.associatedElements[i] is MenuItem) + { + // MenuItem Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].DesiredSize; + this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint( + new Point( + elementSize.Height / 2.0 + 2, + elementSize.Height / 2.0 + 2), this.AdornedElement); + } + else if (((FrameworkElement)this.associatedElements[i]).Parent is BackstageTabControl) + { + // Backstage Items Exclusive Placement + var keyTipSize = this.keyTips[i].DesiredSize; + var elementSize = this.associatedElements[i].DesiredSize; + var parent = (UIElement)((FrameworkElement)this.associatedElements[i]).Parent; + var positionInParent = this.associatedElements[i].TranslatePoint(default(Point), parent); + this.keyTipPositions[i] = parent.TranslatePoint( + new Point( + 5, + positionInParent.Y + (elementSize.Height / 2.0 - keyTipSize.Height)), this.AdornedElement); + } + else + { + if ((RibbonProperties.GetSize(this.associatedElements[i]) != RibbonControlSize.Large) + || (this.associatedElements[i] is Spinner) + || (this.associatedElements[i] is ComboBox) + || (this.associatedElements[i] is TextBox) + || (this.associatedElements[i] is CheckBox)) + { + var withinRibbonToolbar = IsWithinRibbonToolbarInTwoLine(this.associatedElements[i]); + var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.keyTips[i].DesiredSize.Width / 2.0, this.keyTips[i].DesiredSize.Height / 2.0), this.AdornedElement); + + // Snapping to rows if it present + if (rows != null) + { + var index = 0; + var mindistance = Math.Abs(rows[0] - translatedPoint.Y); + for (var j = 1; j < rows.Length; j++) + { + if (withinRibbonToolbar && j == 1) + { + continue; + } + + var distance = Math.Abs(rows[j] - translatedPoint.Y); + if (distance < mindistance) + { + mindistance = distance; + index = j; + } + } + + translatedPoint.Y = rows[index] - this.keyTips[i].DesiredSize.Height / 2.0; + } + + this.keyTipPositions[i] = translatedPoint; + } + else + { + var translatedPoint = this.associatedElements[i].TranslatePoint(new Point(this.associatedElements[i].DesiredSize.Width / 2.0 - this.keyTips[i].DesiredSize.Width / 2.0, this.associatedElements[i].DesiredSize.Height - 8), this.AdornedElement); + if (rows != null) + { + translatedPoint.Y = rows[2] - this.keyTips[i].DesiredSize.Height / 2.0; + } + + this.keyTipPositions[i] = translatedPoint; + } + } + } + } + + // Determines whether the element is children to RibbonToolBar + private static bool IsWithinRibbonToolbarInTwoLine(DependencyObject element) + { + var parent = LogicalTreeHelper.GetParent(element) as UIElement; + var ribbonToolBar = parent as RibbonToolBar; + if (ribbonToolBar != null) + { + var definition = ribbonToolBar.GetCurrentLayoutDefinition(); + if (definition == null) + { + return false; + } + + if (definition.RowCount == 2 || definition.Rows.Count == 2) + { + return true; + } + + return false; + } + + if (parent == null) + { + return false; + } + + return IsWithinRibbonToolbarInTwoLine(parent); + } + + // Determines whether the element is children to quick access toolbar + private static bool IsWithinQuickAccessToolbar(DependencyObject element) + { + var parent = LogicalTreeHelper.GetParent(element) as UIElement; + if (parent is QuickAccessToolBar) + { + return true; + } + + if (parent == null) + { + return false; + } + + return IsWithinQuickAccessToolbar(parent); + } + + /// + /// Gets visual children count + /// + protected override int VisualChildrenCount + { + get + { + return this.keyTips.Count; + } + } + + /// + /// Returns a child at the specified index from a collection of child elements + /// + /// The zero-based index of the requested child element in the collection + /// The requested child element + protected override Visual GetVisualChild(int index) + { + return this.keyTips[index]; + } + + #endregion + + #region Logging + + [SuppressMessage("Microsoft.Performance", "CA1822")] + [SuppressMessage("Microsoft.Performance", "CA1801")] + [Conditional("DEBUG")] + private void Log(string format, params object[] args) + { + var name = this.AdornedElement.GetType().Name; + + var headeredControl = this.AdornedElement as IHeaderedControl; + if (headeredControl != null) + { + name += $" ({headeredControl.Header})"; + } + + var formatted = string.Format(format, args); + Debug.WriteLine($"{$"[{name}] "}{formatted}", "KeyTipAdorner"); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/AttachedProperties/RibbonProperties.cs b/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs similarity index 96% rename from Fluent/AttachedProperties/RibbonProperties.cs rename to Fluent.Ribbon/AttachedProperties/RibbonProperties.cs index 0c93ac927..a8a5ec029 100644 --- a/Fluent/AttachedProperties/RibbonProperties.cs +++ b/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs @@ -1,169 +1,169 @@ -namespace Fluent -{ - using System.Diagnostics.CodeAnalysis; - using System.Windows; - using System.Windows.Media; - using Fluent.Extensibility; - - /// - /// Attached Properties for the Fluent Ribbon library - /// - public class RibbonProperties - { - #region TitleBarHeight Property - - /// - /// Using a DependencyProperty as the backing store for TitleBarHeight. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TitleBarHeightProperty = - DependencyProperty.RegisterAttached("TitleBarHeight", typeof(double), typeof(RibbonProperties), - new FrameworkPropertyMetadata(25D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// Sets TitleBarHeight for element - /// - public static void SetTitleBarHeight(UIElement element, double value) - { - element.SetValue(TitleBarHeightProperty, value); - } - - /// - /// Gets TitleBarHeight for element - /// - [AttachedPropertyBrowsableForType(typeof(Ribbon))] - [AttachedPropertyBrowsableForType(typeof(RibbonTitleBar))] - [AttachedPropertyBrowsableForType(typeof(RibbonWindow))] - public static double GetTitleBarHeight(UIElement element) - { - return (double)element.GetValue(TitleBarHeightProperty); - } - - #endregion - - #region Size Property - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = - DependencyProperty.RegisterAttached("Size", typeof(RibbonControlSize), typeof(RibbonProperties), - new FrameworkPropertyMetadata(RibbonControlSize.Large, - FrameworkPropertyMetadataOptions.AffectsArrange | - FrameworkPropertyMetadataOptions.AffectsMeasure | - FrameworkPropertyMetadataOptions.AffectsRender | - FrameworkPropertyMetadataOptions.AffectsParentArrange | - FrameworkPropertyMetadataOptions.AffectsParentMeasure, - OnSizePropertyChanged) - ); - - private static void OnSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var sink = d as IRibbonSizeChangedSink; - - if (sink == null) - { - return; - } - - sink.OnSizePropertyChanged((RibbonControlSize)e.OldValue, (RibbonControlSize)e.NewValue); - } - - /// - /// Sets SizeDefinition for element - /// - public static void SetSize(DependencyObject element, RibbonControlSize value) - { - element.SetValue(SizeProperty, value); - } - - /// - /// Gets SizeDefinition for element - /// - public static RibbonControlSize GetSize(DependencyObject element) - { - return (RibbonControlSize)element.GetValue(SizeProperty); - } - - #endregion - - #region SizeDefinition Property - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = - DependencyProperty.RegisterAttached("SizeDefinition", typeof(RibbonControlSizeDefinition), typeof(RibbonProperties), - new FrameworkPropertyMetadata(new RibbonControlSizeDefinition(RibbonControlSize.Large, RibbonControlSize.Middle, RibbonControlSize.Small), - FrameworkPropertyMetadataOptions.AffectsArrange | - FrameworkPropertyMetadataOptions.AffectsMeasure | - FrameworkPropertyMetadataOptions.AffectsRender | - FrameworkPropertyMetadataOptions.AffectsParentArrange | - FrameworkPropertyMetadataOptions.AffectsParentMeasure, - OnSizeDefinitionPropertyChanged)); - - /// - /// Gets SizeDefinition for element - /// - public static RibbonControlSizeDefinition GetSizeDefinition(DependencyObject element) - { - return (RibbonControlSizeDefinition)element.GetValue(SizeDefinitionProperty); - } - - /// - /// Sets SizeDefinition for element - /// - public static void SetSizeDefinition(DependencyObject element, RibbonControlSizeDefinition value) - { - element.SetValue(SizeDefinitionProperty, value); - } - - // Handles RibbonSizeDefinitionProperty changes - internal static void OnSizeDefinitionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - // Find parent group box - var groupBox = FindParentRibbonGroupBox(d); - var element = (UIElement)d; - - if (groupBox != null) - { - SetAppropriateSize(element, groupBox.State); - } - else - { - SetAppropriateSize(element, RibbonGroupBoxState.Large); - } - } - - // Finds parent group box - [SuppressMessage("Microsoft.Performance", "CA1800")] - internal static RibbonGroupBox FindParentRibbonGroupBox(DependencyObject o) - { - while (!(o is RibbonGroupBox)) - { - o = VisualTreeHelper.GetParent(o) ?? LogicalTreeHelper.GetParent(o); - if (o == null) - { - break; - } - } - - return (RibbonGroupBox)o; - } - - /// - /// Sets appropriate size of the control according to the - /// given group box state and control's size definition - /// - /// UI Element - /// Group box state - public static void SetAppropriateSize(DependencyObject element, RibbonGroupBoxState state) - { - SetSize(element, GetSizeDefinition(element).GetSize(state)); - } - - #endregion - } +namespace Fluent +{ + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Media; + using Fluent.Extensibility; + + /// + /// Attached Properties for the Fluent Ribbon library + /// + public class RibbonProperties + { + #region TitleBarHeight Property + + /// + /// Using a DependencyProperty as the backing store for TitleBarHeight. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TitleBarHeightProperty = + DependencyProperty.RegisterAttached("TitleBarHeight", typeof(double), typeof(RibbonProperties), + new FrameworkPropertyMetadata(27D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// Sets TitleBarHeight for element + /// + public static void SetTitleBarHeight(UIElement element, double value) + { + element.SetValue(TitleBarHeightProperty, value); + } + + /// + /// Gets TitleBarHeight for element + /// + [AttachedPropertyBrowsableForType(typeof(Ribbon))] + [AttachedPropertyBrowsableForType(typeof(RibbonTitleBar))] + [AttachedPropertyBrowsableForType(typeof(RibbonWindow))] + public static double GetTitleBarHeight(UIElement element) + { + return (double)element.GetValue(TitleBarHeightProperty); + } + + #endregion + + #region Size Property + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = + DependencyProperty.RegisterAttached("Size", typeof(RibbonControlSize), typeof(RibbonProperties), + new FrameworkPropertyMetadata(RibbonControlSize.Large, + FrameworkPropertyMetadataOptions.AffectsArrange | + FrameworkPropertyMetadataOptions.AffectsMeasure | + FrameworkPropertyMetadataOptions.AffectsRender | + FrameworkPropertyMetadataOptions.AffectsParentArrange | + FrameworkPropertyMetadataOptions.AffectsParentMeasure, + OnSizePropertyChanged) + ); + + private static void OnSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var sink = d as IRibbonSizeChangedSink; + + if (sink == null) + { + return; + } + + sink.OnSizePropertyChanged((RibbonControlSize)e.OldValue, (RibbonControlSize)e.NewValue); + } + + /// + /// Sets SizeDefinition for element + /// + public static void SetSize(DependencyObject element, RibbonControlSize value) + { + element.SetValue(SizeProperty, value); + } + + /// + /// Gets SizeDefinition for element + /// + public static RibbonControlSize GetSize(DependencyObject element) + { + return (RibbonControlSize)element.GetValue(SizeProperty); + } + + #endregion + + #region SizeDefinition Property + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = + DependencyProperty.RegisterAttached("SizeDefinition", typeof(RibbonControlSizeDefinition), typeof(RibbonProperties), + new FrameworkPropertyMetadata(new RibbonControlSizeDefinition(RibbonControlSize.Large, RibbonControlSize.Middle, RibbonControlSize.Small), + FrameworkPropertyMetadataOptions.AffectsArrange | + FrameworkPropertyMetadataOptions.AffectsMeasure | + FrameworkPropertyMetadataOptions.AffectsRender | + FrameworkPropertyMetadataOptions.AffectsParentArrange | + FrameworkPropertyMetadataOptions.AffectsParentMeasure, + OnSizeDefinitionPropertyChanged)); + + /// + /// Gets SizeDefinition for element + /// + public static RibbonControlSizeDefinition GetSizeDefinition(DependencyObject element) + { + return (RibbonControlSizeDefinition)element.GetValue(SizeDefinitionProperty); + } + + /// + /// Sets SizeDefinition for element + /// + public static void SetSizeDefinition(DependencyObject element, RibbonControlSizeDefinition value) + { + element.SetValue(SizeDefinitionProperty, value); + } + + // Handles RibbonSizeDefinitionProperty changes + internal static void OnSizeDefinitionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // Find parent group box + var groupBox = FindParentRibbonGroupBox(d); + var element = (UIElement)d; + + if (groupBox != null) + { + SetAppropriateSize(element, groupBox.State); + } + else + { + SetAppropriateSize(element, RibbonGroupBoxState.Large); + } + } + + // Finds parent group box + [SuppressMessage("Microsoft.Performance", "CA1800")] + internal static RibbonGroupBox FindParentRibbonGroupBox(DependencyObject o) + { + while (!(o is RibbonGroupBox)) + { + o = VisualTreeHelper.GetParent(o) ?? LogicalTreeHelper.GetParent(o); + if (o == null) + { + break; + } + } + + return (RibbonGroupBox)o; + } + + /// + /// Sets appropriate size of the control according to the + /// given group box state and control's size definition + /// + /// UI Element + /// Group box state + public static void SetAppropriateSize(DependencyObject element, RibbonGroupBoxState state) + { + SetSize(element, GetSizeDefinition(element).GetSize(state)); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/BackstageButton.cs b/Fluent.Ribbon/BackstageButton.cs similarity index 97% rename from Fluent/BackstageButton.cs rename to Fluent.Ribbon/BackstageButton.cs index aae7aa73f..203273c6e 100644 --- a/Fluent/BackstageButton.cs +++ b/Fluent.Ribbon/BackstageButton.cs @@ -1,148 +1,148 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Data; - -namespace Fluent -{ - /// - /// Represents backstage button - /// - public class BackstageButton:RibbonControl - { - #region Properties - - /// - /// Gets or sets Backstage - /// - public Backstage Backstage - { - get { return (Backstage)GetValue(BackstageProperty); } - set { SetValue(BackstageProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Backstage. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty BackstageProperty = - DependencyProperty.Register("Backstage", typeof(object), - typeof(BackstageButton), new UIPropertyMetadata(null)); - - /// - /// Gets or sets whether backstage is shown - /// - public bool IsOpen - { - get { return (bool)GetValue(IsOpenProperty); } - set { SetValue(IsOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsOpenProperty = - DependencyProperty.Register("IsOpen", typeof(bool), - typeof(BackstageButton), new UIPropertyMetadata(false)); - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - ArrayList list = new ArrayList(); - list.Add(Backstage); - return list.GetEnumerator(); - } - } - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static BackstageButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageButton), new FrameworkPropertyMetadata(typeof(BackstageButton))); - // Disable QAT for this control - CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(BackstageButton), new FrameworkPropertyMetadata(false)); - } - - /// - /// Default constructor - /// - public BackstageButton() - { - Backstage = new Backstage(); - Binding binding = new Binding("Background"); - binding.Source = this; - Backstage.SetBinding(Backstage.BackgroundProperty, binding); - AddLogicalChild(Backstage); - } - - /// - /// Handles click event - /// - void Click() - { - IsOpen = !IsOpen; - } - - #endregion - - #region Overrides - - /// - /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDownrouted event reaches an element - /// in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) - { - Click(); - } - - /// - /// Handles key tip pressed - /// - public override void OnKeyTipPressed() - { - Click(); - base.OnKeyTipPressed(); - } - - #endregion - - #region Quick Access Toolbar - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - throw new NotImplementedException(); - } - - #endregion - } -} +#region Copyright and License Information +// Fluent Ribbon Control Suite +// http://fluent.codeplex.com/ +// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. +// +// Distributed under the terms of the Microsoft Public License (Ms-PL). +// The license is available online http://fluent.codeplex.com/license +#endregion + +using System; +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Data; + +namespace Fluent +{ + /// + /// Represents backstage button + /// + public class BackstageButton:RibbonControl + { + #region Properties + + /// + /// Gets or sets Backstage + /// + public Backstage Backstage + { + get { return (Backstage)GetValue(BackstageProperty); } + set { SetValue(BackstageProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Backstage. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty BackstageProperty = + DependencyProperty.Register("Backstage", typeof(object), + typeof(BackstageButton), new UIPropertyMetadata(null)); + + /// + /// Gets or sets whether backstage is shown + /// + public bool IsOpen + { + get { return (bool)GetValue(IsOpenProperty); } + set { SetValue(IsOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsOpenProperty = + DependencyProperty.Register("IsOpen", typeof(bool), + typeof(BackstageButton), new UIPropertyMetadata(false)); + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + ArrayList list = new ArrayList(); + list.Add(Backstage); + return list.GetEnumerator(); + } + } + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static BackstageButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageButton), new FrameworkPropertyMetadata(typeof(BackstageButton))); + // Disable QAT for this control + CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(BackstageButton), new FrameworkPropertyMetadata(false)); + } + + /// + /// Default constructor + /// + public BackstageButton() + { + Backstage = new Backstage(); + Binding binding = new Binding("Background"); + binding.Source = this; + Backstage.SetBinding(Backstage.BackgroundProperty, binding); + AddLogicalChild(Backstage); + } + + /// + /// Handles click event + /// + void Click() + { + IsOpen = !IsOpen; + } + + #endregion + + #region Overrides + + /// + /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDownrouted event reaches an element + /// in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e) + { + Click(); + } + + /// + /// Handles key tip pressed + /// + public override void OnKeyTipPressed() + { + Click(); + base.OnKeyTipPressed(); + } + + #endregion + + #region Quick Access Toolbar + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/Fluent/Controls/ApplicationMenu.cs b/Fluent.Ribbon/Controls/ApplicationMenu.cs similarity index 89% rename from Fluent/Controls/ApplicationMenu.cs rename to Fluent.Ribbon/Controls/ApplicationMenu.cs index bc6ad1356..a36bd6f4b 100644 --- a/Fluent/Controls/ApplicationMenu.cs +++ b/Fluent.Ribbon/Controls/ApplicationMenu.cs @@ -1,132 +1,121 @@ -#region Copyright and License Information - -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license - -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; - -namespace Fluent -{ - /// - /// Represents backstage button - /// - public class ApplicationMenu : DropDownButton - { - #region Properties - - /// - /// Gets or sets width of right content - /// - public double RightPaneWidth - { - get { return (double)this.GetValue(RightPaneWidthProperty); } - set { this.SetValue(RightPaneWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for RightContentWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty RightPaneWidthProperty = - DependencyProperty.Register("RightPaneWidth", typeof(double), typeof(ApplicationMenu), new UIPropertyMetadata(300.0)); - - /// - /// Gets or sets application menu right pane content - /// - public object RightPaneContent - { - get { return this.GetValue(RightPaneContentProperty); } - set { this.SetValue(RightPaneContentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for RightContent. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty RightPaneContentProperty = - DependencyProperty.Register("RightPaneContent", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null)); - - /// - /// Gets or sets application menu bottom pane content - /// - public object FooterPaneContent - { - get { return this.GetValue(FooterPaneContentProperty); } - set { this.SetValue(FooterPaneContentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for BottomContent. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty FooterPaneContentProperty = - DependencyProperty.Register("FooterPaneContent", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null)); - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static ApplicationMenu() - { - var type = typeof (ApplicationMenu); - - // Override style metadata - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - // Disable QAT for this control - CanAddToQuickAccessToolBarProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false)); - // Make default KeyTip - KeyTipProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, null, CoerceKeyTipKeys)); - StyleProperty.OverrideMetadata(typeof(ApplicationMenu), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = ((FrameworkElement) d).TryFindResource(typeof(ApplicationMenu)); - } - - return basevalue; - } - - static object CoerceKeyTipKeys(DependencyObject d, object basevalue) - { - return basevalue ?? Ribbon.Localization.BackstageButtonKeyTip; - } - - /// - /// Default constructor - /// - public ApplicationMenu() - { - this.CoerceValue(KeyTipProperty); - } - - #endregion - - #region Quick Access Toolbar - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - throw new NotImplementedException(); - } - - #endregion - } +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; + +namespace Fluent +{ + /// + /// Represents backstage button + /// + public class ApplicationMenu : DropDownButton + { + #region Properties + + /// + /// Gets or sets width of right content + /// + public double RightPaneWidth + { + get { return (double)this.GetValue(RightPaneWidthProperty); } + set { this.SetValue(RightPaneWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for RightContentWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty RightPaneWidthProperty = + DependencyProperty.Register("RightPaneWidth", typeof(double), typeof(ApplicationMenu), new UIPropertyMetadata(300.0)); + + /// + /// Gets or sets application menu right pane content + /// + public object RightPaneContent + { + get { return this.GetValue(RightPaneContentProperty); } + set { this.SetValue(RightPaneContentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for RightContent. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty RightPaneContentProperty = + DependencyProperty.Register("RightPaneContent", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null)); + + /// + /// Gets or sets application menu bottom pane content + /// + public object FooterPaneContent + { + get { return this.GetValue(FooterPaneContentProperty); } + set { this.SetValue(FooterPaneContentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for BottomContent. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty FooterPaneContentProperty = + DependencyProperty.Register("FooterPaneContent", typeof(object), typeof(ApplicationMenu), new UIPropertyMetadata(null)); + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static ApplicationMenu() + { + var type = typeof (ApplicationMenu); + + // Override style metadata + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + // Disable QAT for this control + CanAddToQuickAccessToolBarProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false)); + // Make default KeyTip + KeyTipProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, null, CoerceKeyTipKeys)); + StyleProperty.OverrideMetadata(typeof(ApplicationMenu), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = ((FrameworkElement) d).TryFindResource(typeof(ApplicationMenu)); + } + + return basevalue; + } + + static object CoerceKeyTipKeys(DependencyObject d, object basevalue) + { + return basevalue ?? Ribbon.Localization.BackstageButtonKeyTip; + } + + /// + /// Default constructor + /// + public ApplicationMenu() + { + this.CoerceValue(KeyTipProperty); + } + + #endregion + + #region Quick Access Toolbar + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + throw new NotImplementedException(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/Backstage.cs b/Fluent.Ribbon/Controls/Backstage.cs similarity index 76% rename from Fluent/Controls/Backstage.cs rename to Fluent.Ribbon/Controls/Backstage.cs index 35cae43d8..e134556f9 100644 --- a/Fluent/Controls/Backstage.cs +++ b/Fluent.Ribbon/Controls/Backstage.cs @@ -1,716 +1,733 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - using System.Threading; - using System.Threading.Tasks; - using System.Windows.Controls; - using System.Windows.Threading; - using Fluent.Extensions; - using Fluent.Internal; - - /// - /// Represents backstage button - /// - [ContentProperty("Content")] - public class Backstage : RibbonControl - { - private static readonly object syncIsOpen = new object(); - - #region Events - - /// - /// Occurs when IsOpen has been changed - /// - public event DependencyPropertyChangedEventHandler IsOpenChanged; - - #endregion - - #region Fields - - // Adorner for backstage - BackstageAdorner adorner; - - #endregion - - #region Properties - - #region IsOpen - - /// - /// Gets or sets whether backstage is shown - /// - public bool IsOpen - { - get { return (bool)this.GetValue(IsOpenProperty); } - set { this.SetValue(IsOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsOpenProperty = - DependencyProperty.Register("IsOpen", typeof(bool), - typeof(Backstage), new UIPropertyMetadata(false, OnIsOpenChanged)); - - /// - /// Gets or sets the duration for the hide animation - /// - public Duration HideAnimationDuration - { - get { return (Duration)this.GetValue(HideAnimationDurationProperty); } - set { this.SetValue(HideAnimationDurationProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HideAnimationDuration. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HideAnimationDurationProperty = DependencyProperty.Register("HideAnimationDuration", typeof(Duration), typeof(Backstage), new PropertyMetadata(null)); - - /// - /// Gets or sets whether context tabs on the titlebar should be hidden when backstage is open - /// - public bool HideContextTabsOnOpen - { - get { return (bool)this.GetValue(HideContextTabsOnOpenProperty); } - set { this.SetValue(HideContextTabsOnOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HideContextTabsOnOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HideContextTabsOnOpenProperty = DependencyProperty.Register("HideContextTabsOnOpen", typeof(bool), typeof(Backstage), new PropertyMetadata(false)); - - /// - /// Gets or sets whether to close the backstage when Esc is pressed - /// - public bool CloseOnEsc - { - get { return (bool)this.GetValue(CloseOnEscProperty); } - set { this.SetValue(CloseOnEscProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CloseOnEsc. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CloseOnEscProperty = DependencyProperty.Register("CloseOnEsc", typeof(bool), typeof(Backstage), new PropertyMetadata(true)); - - private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var backstage = (Backstage)d; - - lock (syncIsOpen) - { - if ((bool)e.NewValue) - { - backstage.Show(); - } - else - { - if (backstage.HideAnimationDuration.HasTimeSpan) - { - var timespan = backstage.HideAnimationDuration.TimeSpan; - - Task.Factory.StartNew(() => - { - Thread.Sleep(timespan); - - backstage.Dispatcher.RunInDispatcher(backstage.Hide); - }); - } - else - { - backstage.Hide(); - } - } - - // Invoke the event - if (backstage.IsOpenChanged != null) - { - backstage.IsOpenChanged(backstage, e); - } - } - } - - #endregion - - #region Content - - /// - /// Gets or sets content of the backstage - /// - public UIElement Content - { - get { return (UIElement)this.GetValue(ContentProperty); } - set { this.SetValue(ContentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Content. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ContentProperty = - DependencyProperty.Register("Content", typeof(UIElement), typeof(Backstage), - new UIPropertyMetadata(null, OnContentChanged)); - - static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var backstage = (Backstage)d; - if (e.OldValue != null) - { - backstage.RemoveLogicalChild(e.OldValue); - } - - if (e.NewValue != null) - { - backstage.AddLogicalChild(e.NewValue); - } - } - - #endregion - - #region LogicalChildren - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - if (this.Content != null) - { - yield return this.Content; - } - } - } - - #endregion - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static Backstage() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(typeof(Backstage))); - // Disable QAT for this control - CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(false)); - - KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle)); - } - - /// - /// Default constructor - /// - public Backstage() - { - this.Loaded += this.OnBackstageLoaded; - this.Unloaded += this.OnBackstageUnloaded; - } - - private void OnPopupDismiss(object sender, DismissPopupEventArgs e) - { - this.IsOpen = false; - } - - #endregion - - #region Methods - - // Handles click event - private void Click() - { - this.IsOpen = !this.IsOpen; - } - - #region Show / Hide - - // We have to collapse WindowsFormsHost while Backstate is open - private readonly Dictionary collapsedElements = new Dictionary(); - - // Saved window sizes - private double savedWindowMinWidth = double.NaN; - private double savedWindowMinHeight = double.NaN; - private double savedWindowWidth = double.NaN; - private double savedWindowHeight = double.NaN; - - // Opens backstage on an Adorner layer - private void Show() - { - // don't open the backstage while in design mode - if (DesignerProperties.GetIsInDesignMode(this)) - { - return; - } - - if (this.IsLoaded == false) - { - this.Loaded += this.OnDelayedShow; - return; - } - - if (this.Content == null) - { - return; - } - - this.CreateAndAttachBackstageAdorner(); - - this.ShowAdorner(); - - var ribbon = this.FindRibbon(); - if (ribbon != null) - { - ribbon.TabControl.IsDropDownOpen = false; - ribbon.TabControl.HighlightSelectedItem = false; - ribbon.TabControl.RequestBackstageClose += this.OnTabControlRequestBackstageClose; - - // Disable QAT & title bar - if (ribbon.QuickAccessToolBar != null) - { - ribbon.QuickAccessToolBar.IsEnabled = false; - } - - if (ribbon.TitleBar != null) - { - ribbon.TitleBar.IsEnabled = false; - ribbon.TitleBar.HideContextTabs = this.HideContextTabsOnOpen; - } - } - - var window = Window.GetWindow(this); - - this.SaveWindowSize(window); - this.SaveWindowMinSize(window); - - if (window != null) - { - window.KeyDown += this.HandleWindowKeyDown; - - - if (this.savedWindowMinWidth < 500) - { - window.MinWidth = 500; - } - - if (this.savedWindowMinHeight < 400) - { - window.MinHeight = 400; - } - - window.SizeChanged += this.OnWindowSizeChanged; - - // We have to collapse WindowsFormsHost while Backstage is open - this.CollapseWindowsFormsHosts(window); - } - - var content = this.Content as IInputElement; - if (content != null) - { - content.Focus(); - } - } - - private void ShowAdorner() - { - if (this.adorner == null) - { - return; - } - - this.adorner.Visibility = Visibility.Visible; - } - - private void HideAdorner() - { - if (this.adorner == null) - { - return; - } - - this.adorner.Visibility = Visibility.Collapsed; - } - - private void CreateAndAttachBackstageAdorner() - { - if (this.adorner != null) - { - return; - } - - FrameworkElement topLevelElement = null; - - if (DesignerProperties.GetIsInDesignMode(this)) - { - // TODO: in design mode it is required to use design time adorner - topLevelElement = (FrameworkElement)VisualTreeHelper.GetParent(this); - } - else - { - var mainWindow = Window.GetWindow(this); - if (mainWindow == null) - { - return; - } - - var content = mainWindow.Content; - - var fe = content as FrameworkElement; // Content may be an arbitrary .NET object when set using a databinding and using data templates. - - if (fe != null) - { - topLevelElement = fe; - } - else - { - // If Content is not a FrameworkElement we try to find the ContentPresenter - // containing the template to display the content. - var contentPresenter = UIHelper.FindVisualChild(mainWindow); - - if (contentPresenter != null && contentPresenter.Content == content) - { - // set the root element of the template as the top level element. - topLevelElement = (FrameworkElement)VisualTreeHelper.GetChild(contentPresenter, 0); - } - } - } - - if (topLevelElement == null) - { - return; - } - - this.adorner = new BackstageAdorner(topLevelElement, this); - - var layer = AdornerLayer.GetAdornerLayer(this); - layer.Add(this.adorner); - - layer.CommandBindings.Add(new CommandBinding(RibbonCommands.OpenBackstage, - (sender, args) => - { - this.IsOpen = !this.IsOpen; - })); - } - - - private void DestroyAdorner() - { - if (this.adorner == null) - { - return; - } - - var layer = AdornerLayer.GetAdornerLayer(this); - layer.Remove(this.adorner); - - this.adorner.Clear(); - this.adorner = null; - } - - private void OnDelayedShow(object sender, EventArgs args) - { - this.Loaded -= this.OnDelayedShow; - - // Delaying show so everthing can load properly. - // If we don't run this in the background setting IsOpen=true on application start we don't have access to the Bastage from the BackstageTabControl. - this.RunInDispatcherAsync(this.Show, DispatcherPriority.Background); - } - - // Hide backstage - private void Hide() - { - this.Loaded -= this.OnDelayedShow; - - if (this.Content == null) - { - return; - } - - if (!this.IsLoaded - || this.adorner == null) - { - return; - } - - this.HideAdorner(); - - var ribbon = this.FindRibbon(); - if (ribbon != null) - { - ribbon.TabControl.HighlightSelectedItem = true; - ribbon.TabControl.RequestBackstageClose -= this.OnTabControlRequestBackstageClose; - - // Restore enable under QAT & title bar - if (ribbon.QuickAccessToolBar != null) - { - ribbon.QuickAccessToolBar.IsEnabled = true; - ribbon.QuickAccessToolBar.Refresh(); - } - - if (ribbon.TitleBar != null) - { - ribbon.TitleBar.IsEnabled = true; - ribbon.TitleBar.HideContextTabs = false; - } - } - - var window = Window.GetWindow(this); - if (window != null) - { - window.PreviewKeyDown -= this.HandleWindowKeyDown; - window.SizeChanged -= this.OnWindowSizeChanged; - - if (double.IsNaN(this.savedWindowMinWidth) == false - && double.IsNaN(this.savedWindowMinHeight) == false) - { - window.MinWidth = this.savedWindowMinWidth; - window.MinHeight = this.savedWindowMinHeight; - } - - if (double.IsNaN(this.savedWindowWidth) == false - && double.IsNaN(this.savedWindowHeight) == false) - { - window.Width = this.savedWindowWidth; - window.Height = this.savedWindowHeight; - } - } - - // Uncollapse elements - foreach (var element in this.collapsedElements) - { - element.Key.Visibility = element.Value; - } - - this.collapsedElements.Clear(); - } - - // Finds underlying ribbon control - private Ribbon FindRibbon() - { - DependencyObject item = this; - - while (item != null - && !(item is Ribbon)) - { - item = VisualTreeHelper.GetParent(item); - } - - return (Ribbon)item; - } - - private void SaveWindowMinSize(Window window) - { - if (window == null) - { - this.savedWindowMinWidth = double.NaN; - this.savedWindowMinHeight = double.NaN; - return; - } - - this.savedWindowMinWidth = window.MinWidth; - this.savedWindowMinHeight = window.MinHeight; - } - - private void SaveWindowSize(Window window) - { - if (window == null) - { - this.savedWindowWidth = double.NaN; - this.savedWindowHeight = double.NaN; - return; - } - - this.savedWindowWidth = window.ActualWidth; - this.savedWindowHeight = window.ActualHeight; - } - - private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e) - { - this.SaveWindowSize(Window.GetWindow(this)); - } - - private void OnTabControlRequestBackstageClose(object sender, EventArgs e) - { - this.IsOpen = false; - } - - // We have to collapse WindowsFormsHost while Backstage is open - private void CollapseWindowsFormsHosts(DependencyObject parent) - { - if (parent == null) - { - return; - } - - var frameworkElement = parent as FrameworkElement; - - // Do not hide contents in the backstage area - if (parent is BackstageAdorner) return; - - if (frameworkElement != null) - { - if ((parent is HwndHost) && - frameworkElement.Visibility != Visibility.Collapsed) - { - this.collapsedElements.Add(frameworkElement, frameworkElement.Visibility); - frameworkElement.Visibility = Visibility.Collapsed; - return; - } - } - - // Traverse visual tree - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) - { - this.CollapseWindowsFormsHosts(VisualTreeHelper.GetChild(parent, i)); - } - } - - /// - /// Invoked when an unhandled attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The that contains the event data. - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.Handled) - { - return; - } - - switch (e.Key) - { - case Key.Enter: - case Key.Space: - if (this.IsFocused) - { - this.IsOpen = !this.IsOpen; - e.Handled = true; - } - break; - } - - base.OnKeyDown(e); - } - - // Handles backstage Esc key keydown - private void HandleWindowKeyDown(object sender, KeyEventArgs e) - { - if (this.CloseOnEsc && e.Key == Key.Escape) - { - // only handle ESC when the backstage is open - e.Handled = this.IsOpen; - - this.IsOpen = false; - } - } - - private void OnBackstageLoaded(object sender, RoutedEventArgs e) - { - this.AddHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); - } - - private void OnBackstageUnloaded(object sender, RoutedEventArgs e) - { - this.RemoveHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); - } - - #endregion - - #endregion - - #region Overrides - - /// - /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDownrouted event reaches an element - /// in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - this.Click(); - } - - /// - /// Handles key tip pressed - /// - public override void OnKeyTipPressed() - { - this.IsOpen = true; - base.OnKeyTipPressed(); - } - - /// - /// Handles back navigation with KeyTips - /// - public override void OnKeyTipBack() - { - this.IsOpen = false; - base.OnKeyTipBack(); - } - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (this.IsOpen) - { - this.Hide(); - } - - this.DestroyAdorner(); - - if (this.IsOpen) - { - this.Show(); - } - } - - #endregion - - #region Quick Access Toolbar - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - throw new NotImplementedException(); - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Documents; + using System.Windows.Input; + using System.Windows.Interop; + using System.Windows.Markup; + using System.Windows.Media; + using System.Windows.Threading; + using System.Threading; + using System.Threading.Tasks; + using Fluent.Extensions; + using Fluent.Internal; + + /// + /// Represents backstage button + /// + [ContentProperty(nameof(Content))] + public class Backstage : RibbonControl + { + private static readonly object syncIsOpen = new object(); + + /// + /// Occurs when IsOpen has been changed + /// + public event DependencyPropertyChangedEventHandler IsOpenChanged; + + // Adorner for backstage + private BackstageAdorner adorner; + + #region Properties + + /// + /// Gets or sets whether backstage is shown + /// + public bool IsOpen + { + get { return (bool)this.GetValue(IsOpenProperty); } + set { this.SetValue(IsOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsOpenProperty = + DependencyProperty.Register(nameof(IsOpen), typeof(bool), typeof(Backstage), new UIPropertyMetadata(false, OnIsOpenChanged)); + + /// + /// Gets or sets the duration for the hide animation + /// + public Duration HideAnimationDuration + { + get { return (Duration)this.GetValue(HideAnimationDurationProperty); } + set { this.SetValue(HideAnimationDurationProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HideAnimationDuration. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HideAnimationDurationProperty = + DependencyProperty.Register(nameof(HideAnimationDuration), typeof(Duration), typeof(Backstage), new PropertyMetadata(null)); + + /// + /// Gets or sets whether context tabs on the titlebar should be hidden when backstage is open + /// + public bool HideContextTabsOnOpen + { + get { return (bool)this.GetValue(HideContextTabsOnOpenProperty); } + set { this.SetValue(HideContextTabsOnOpenProperty, value); } + } + + /// + /// Gets or sets wether opening or closing should be animated. + /// + public bool IsOpenAnimationEnabled + { + get { return (bool)this.GetValue(IsOpenAnimationEnabledProperty); } + set { this.SetValue(IsOpenAnimationEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpenAnimationEnabled. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsOpenAnimationEnabledProperty = + DependencyProperty.Register(nameof(IsOpenAnimationEnabled), typeof(bool), typeof(Backstage), new UIPropertyMetadata(true)); + + /// + /// Using a DependencyProperty as the backing store for HideContextTabsOnOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HideContextTabsOnOpenProperty = + DependencyProperty.Register(nameof(HideContextTabsOnOpen), typeof(bool), typeof(Backstage), new PropertyMetadata(false)); + + /// + /// Gets or sets whether to close the backstage when Esc is pressed + /// + public bool CloseOnEsc + { + get { return (bool)this.GetValue(CloseOnEscProperty); } + set { this.SetValue(CloseOnEscProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CloseOnEsc. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CloseOnEscProperty = + DependencyProperty.Register(nameof(CloseOnEsc), typeof(bool), typeof(Backstage), new PropertyMetadata(true)); + + private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var backstage = (Backstage)d; + + lock (syncIsOpen) + { + if ((bool)e.NewValue) + { + backstage.Show(); + } + else + { + if (backstage.HideAnimationDuration.HasTimeSpan) + { + var timespan = backstage.HideAnimationDuration.TimeSpan; + + Task.Factory.StartNew(() => + { + Thread.Sleep(timespan); + + backstage.Dispatcher.RunInDispatcher(backstage.Hide); + }); + } + else + { + backstage.Hide(); + } + } + + // Invoke the event + backstage.IsOpenChanged?.Invoke(backstage, e); + } + } + + #region Content + + /// + /// Gets or sets content of the backstage + /// + public UIElement Content + { + get { return (UIElement)this.GetValue(ContentProperty); } + set { this.SetValue(ContentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Content. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ContentProperty = + DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(Backstage), new UIPropertyMetadata(null, OnContentChanged)); + + private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var backstage = (Backstage)d; + if (e.OldValue != null) + { + backstage.RemoveLogicalChild(e.OldValue); + } + + if (e.NewValue != null) + { + backstage.AddLogicalChild(e.NewValue); + } + } + + #endregion + + #region LogicalChildren + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + if (this.Content != null) + { + yield return this.Content; + } + } + } + + #endregion + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static Backstage() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(typeof(Backstage))); + // Disable QAT for this control + CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(false)); + + KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(Backstage), new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle)); + } + + /// + /// Default constructor + /// + public Backstage() + { + this.Loaded += this.OnBackstageLoaded; + this.Unloaded += this.OnBackstageUnloaded; + } + + private void OnPopupDismiss(object sender, DismissPopupEventArgs e) + { + // Only close backstage when popups should always be closed. + // "Always" applies to controls marked with IsDefinitive for example. + if (e.DismissMode != DismissPopupMode.Always) + { + return; + } + + this.IsOpen = false; + } + + #endregion + + #region Methods + + // Handles click event + private void Click() + { + this.IsOpen = !this.IsOpen; + } + + #region Show / Hide + + // We have to collapse WindowsFormsHost while Backstate is open + private readonly Dictionary collapsedElements = new Dictionary(); + + // Saved window sizes + private double savedWindowMinWidth = double.NaN; + private double savedWindowMinHeight = double.NaN; + private double savedWindowWidth = double.NaN; + private double savedWindowHeight = double.NaN; + + /// + /// Shows the + /// + protected virtual bool Show() + { + // don't open the backstage while in design mode + if (DesignerProperties.GetIsInDesignMode(this)) + { + return false; + } + + if (this.IsLoaded == false) + { + this.Loaded += this.OnDelayedShow; + return false; + } + + if (this.Content == null) + { + return false; + } + + this.CreateAndAttachBackstageAdorner(); + + this.ShowAdorner(); + + var ribbon = this.GetParentRibbon(); + if (ribbon != null) + { + ribbon.TabControl.IsDropDownOpen = false; + ribbon.TabControl.HighlightSelectedItem = false; + ribbon.TabControl.RequestBackstageClose += this.OnTabControlRequestBackstageClose; + + // Disable QAT & title bar + if (ribbon.QuickAccessToolBar != null) + { + ribbon.QuickAccessToolBar.IsEnabled = false; + } + + if (ribbon.TitleBar != null) + { + ribbon.TitleBar.IsEnabled = false; + ribbon.TitleBar.HideContextTabs = this.HideContextTabsOnOpen; + } + } + + var window = Window.GetWindow(this); + + this.SaveWindowSize(window); + this.SaveWindowMinSize(window); + + if (window != null) + { + window.KeyDown += this.HandleWindowKeyDown; + + + if (this.savedWindowMinWidth < 500) + { + window.MinWidth = 500; + } + + if (this.savedWindowMinHeight < 400) + { + window.MinHeight = 400; + } + + window.SizeChanged += this.OnWindowSizeChanged; + + // We have to collapse WindowsFormsHost while Backstage is open + this.CollapseWindowsFormsHosts(window); + } + + var content = this.Content as IInputElement; + content?.Focus(); + + return true; + } + + private void ShowAdorner() + { + if (this.adorner == null) + { + return; + } + + this.adorner.Visibility = Visibility.Visible; + } + + private void HideAdorner() + { + if (this.adorner == null) + { + return; + } + + this.adorner.Visibility = Visibility.Collapsed; + } + + private void CreateAndAttachBackstageAdorner() + { + // It's possible that we created an adorner but it's parent AdornerLayer got destroyed. + // If that's the case we have to destroy our adorner. + // This fixes #228 Backstage disappears when changing DontUseDwm + if (this.adorner?.Parent == null) + { + this.DestroyAdorner(); + } + + if (this.adorner != null) + { + return; + } + + FrameworkElement elementToAdorn; + + if (DesignerProperties.GetIsInDesignMode(this)) + { + // TODO: in design mode it is required to use design time adorner + elementToAdorn = (FrameworkElement)VisualTreeHelper.GetParent(this); + } + else + { + elementToAdorn = UIHelper.GetParent(this); + } + + if (elementToAdorn == null) + { + return; + } + + var layer = AdornerLayer.GetAdornerLayer(this); + + if (layer == null) + { + throw new Exception($"AdornerLayer could not be found for {this}."); + } + + this.adorner = new BackstageAdorner(elementToAdorn, this); + layer.Add(this.adorner); + + layer.CommandBindings.Add(new CommandBinding(RibbonCommands.OpenBackstage, HandleOpenBackstageCommandExecuted)); + } + + private static void HandleOpenBackstageCommandExecuted(object sender, ExecutedRoutedEventArgs args) + { + var target = ((BackstageAdorner)args.Source).Backstage; + target.IsOpen = !target.IsOpen; + } + + private void DestroyAdorner() + { + if (this.adorner == null) + { + return; + } + + var layer = AdornerLayer.GetAdornerLayer(this.adorner); + layer?.CommandBindings.Clear(); + layer?.Remove(this.adorner); + + this.adorner.Clear(); + this.adorner = null; + } + + private void OnDelayedShow(object sender, EventArgs args) + { + this.Loaded -= this.OnDelayedShow; + + // Delaying show so everthing can load properly. + // If we don't run this in the background setting IsOpen=true on application start we don't have access to the Bastage from the BackstageTabControl. + this.RunInDispatcherAsync(() => this.Show(), DispatcherPriority.Background); + } + + /// + /// Hides the + /// + protected virtual void Hide() + { + this.Loaded -= this.OnDelayedShow; + + if (this.Content == null) + { + return; + } + + if (!this.IsLoaded + || this.adorner == null) + { + return; + } + + this.HideAdorner(); + + var ribbon = this.GetParentRibbon(); + if (ribbon != null) + { + ribbon.TabControl.HighlightSelectedItem = true; + ribbon.TabControl.RequestBackstageClose -= this.OnTabControlRequestBackstageClose; + + // Restore enable under QAT & title bar + if (ribbon.QuickAccessToolBar != null) + { + ribbon.QuickAccessToolBar.IsEnabled = true; + ribbon.QuickAccessToolBar.Refresh(); + } + + if (ribbon.TitleBar != null) + { + ribbon.TitleBar.IsEnabled = true; + ribbon.TitleBar.HideContextTabs = false; + } + } + + var window = Window.GetWindow(this); + if (window != null) + { + window.PreviewKeyDown -= this.HandleWindowKeyDown; + window.SizeChanged -= this.OnWindowSizeChanged; + + if (double.IsNaN(this.savedWindowMinWidth) == false + && double.IsNaN(this.savedWindowMinHeight) == false) + { + window.MinWidth = this.savedWindowMinWidth; + window.MinHeight = this.savedWindowMinHeight; + } + + if (double.IsNaN(this.savedWindowWidth) == false + && double.IsNaN(this.savedWindowHeight) == false) + { + window.Width = this.savedWindowWidth; + window.Height = this.savedWindowHeight; + } + } + + // Uncollapse elements + foreach (var element in this.collapsedElements) + { + element.Key.Visibility = element.Value; + } + + this.collapsedElements.Clear(); + } + + /// + /// Get the parent . + /// + /// The found or null of no parent could be found. + protected Ribbon GetParentRibbon() + { + DependencyObject item = this; + + while (item != null + && item is Ribbon == false) + { + item = VisualTreeHelper.GetParent(item); + } + + if (item == null) + { + item = this; + + while (item != null && + item is Ribbon == false) + { + item = LogicalTreeHelper.GetParent(item); + } + } + + return (Ribbon)item; + } + + private void SaveWindowMinSize(Window window) + { + if (window == null) + { + this.savedWindowMinWidth = double.NaN; + this.savedWindowMinHeight = double.NaN; + return; + } + + this.savedWindowMinWidth = window.MinWidth; + this.savedWindowMinHeight = window.MinHeight; + } + + private void SaveWindowSize(Window window) + { + if (window == null + || window.WindowState == WindowState.Maximized) + { + this.savedWindowWidth = double.NaN; + this.savedWindowHeight = double.NaN; + return; + } + + this.savedWindowWidth = window.ActualWidth; + this.savedWindowHeight = window.ActualHeight; + } + + private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e) + { + this.SaveWindowSize(Window.GetWindow(this)); + } + + private void OnTabControlRequestBackstageClose(object sender, EventArgs e) + { + this.IsOpen = false; + } + + // We have to collapse WindowsFormsHost while Backstage is open + private void CollapseWindowsFormsHosts(DependencyObject parent) + { + if (parent == null) + { + return; + } + + var frameworkElement = parent as FrameworkElement; + + // Do not hide contents in the backstage area + if (parent is BackstageAdorner) + { + return; + } + + if (frameworkElement != null) + { + if (parent is HwndHost + && frameworkElement.Visibility != Visibility.Collapsed) + { + this.collapsedElements.Add(frameworkElement, frameworkElement.Visibility); + frameworkElement.Visibility = Visibility.Collapsed; + return; + } + } + + // Traverse visual tree + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + this.CollapseWindowsFormsHosts(VisualTreeHelper.GetChild(parent, i)); + } + } + + /// + /// Invoked when an unhandled attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Handled) + { + return; + } + + if (e.Key == Key.Enter + || e.Key == Key.Space) + { + if (this.IsFocused) + { + this.IsOpen = !this.IsOpen; + e.Handled = true; + } + } + + base.OnKeyDown(e); + } + + // Handles backstage Esc key keydown + private void HandleWindowKeyDown(object sender, KeyEventArgs e) + { + if (this.CloseOnEsc == false + || e.Key != Key.Escape) + { + return; + } + + // only handle ESC when the backstage is open + e.Handled = this.IsOpen; + + this.IsOpen = false; + } + + private void OnBackstageLoaded(object sender, RoutedEventArgs e) + { + this.AddHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); + } + + private void OnBackstageUnloaded(object sender, RoutedEventArgs e) + { + this.RemoveHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); + } + + #endregion + + #endregion + + #region Overrides + + /// + /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDownrouted event reaches an element + /// in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (ReferenceEquals(e.Source, this) == false) + { + return; + } + + this.Click(); + } + + /// + /// Handles key tip pressed + /// + public override void OnKeyTipPressed() + { + this.IsOpen = true; + base.OnKeyTipPressed(); + } + + /// + /// Handles back navigation with KeyTips + /// + public override void OnKeyTipBack() + { + this.IsOpen = false; + base.OnKeyTipBack(); + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (this.IsOpen) + { + this.Hide(); + } + + this.DestroyAdorner(); + + if (this.IsOpen) + { + this.Show(); + } + } + + #endregion + + #region Quick Access Toolbar + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + throw new NotImplementedException(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/BackstageAdorner.cs b/Fluent.Ribbon/Controls/BackstageAdorner.cs similarity index 86% rename from Fluent/Controls/BackstageAdorner.cs rename to Fluent.Ribbon/Controls/BackstageAdorner.cs index 0599a5ae7..46a89abcd 100644 --- a/Fluent/Controls/BackstageAdorner.cs +++ b/Fluent.Ribbon/Controls/BackstageAdorner.cs @@ -1,123 +1,114 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Windows; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents adorner for Backstage - /// - internal class BackstageAdorner : Adorner - { - // Backstage - private readonly Backstage backstage; - - // Content of Backstage - private readonly UIElement backstageContent; - - // Collection of visual children - private readonly VisualCollection visualChildren; - - /// - /// Constructor - /// - /// Adorned element - /// Backstage - public BackstageAdorner(FrameworkElement adornedElement, Backstage backstage) - : base(adornedElement) - { - KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Cycle); - - this.backstage = backstage; - this.backstageContent = this.backstage.Content; - - this.visualChildren = new VisualCollection(this) - { - this.backstageContent - }; - - // TODO: fix it! (below ugly workaround) in measureoverride we cannot get RenderSize, we must use DesiredSize - // Syncronize with visual size - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - CompositionTarget.Rendering += this.CompositionTargetRendering; - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - CompositionTarget.Rendering -= this.CompositionTargetRendering; - } - - private void CompositionTargetRendering(object sender, EventArgs e) - { - if (this.RenderSize != this.AdornedElement.RenderSize) - { - this.InvalidateMeasure(); - } - } - - public void Clear() - { - this.visualChildren.Clear(); - } - - #region Layout & Visual Children - - /// - /// Positions child elements and determines - /// a size for the control - /// - /// The final area within the parent - /// that this element should use to arrange - /// itself and its children - /// The actual size used - protected override Size ArrangeOverride(Size finalSize) - { - this.backstageContent.Arrange(new Rect(0, 0, finalSize.Width, Math.Max(0, finalSize.Height))); - return finalSize; - } - - /// - /// Measures KeyTips - /// - /// The available size that this element can give to child elements. - /// The size that the groups container determines it needs during - /// layout, based on its calculations of child element sizes. - /// - protected override Size MeasureOverride(Size constraint) - { - // TODO: fix it! (below ugly workaround) in measureoverride we cannot get RenderSize, we must use DesiredSize - this.backstageContent.Measure(new Size(this.AdornedElement.RenderSize.Width, Math.Max(0, this.AdornedElement.RenderSize.Height))); - return this.AdornedElement.RenderSize; - } - - /// - /// Gets visual children count - /// - protected override int VisualChildrenCount { get { return this.visualChildren.Count; } } - - /// - /// Returns a child at the specified index from a collection of child elements - /// - /// The zero-based index of the requested child element in the collection - /// The requested child element - protected override Visual GetVisualChild(int index) { return this.visualChildren[index]; } - - #endregion - } +using System; +using System.Windows; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents adorner for Backstage + /// + internal class BackstageAdorner : Adorner + { + // Backstage + public readonly Backstage Backstage; + + // Content of Backstage + private readonly UIElement backstageContent; + + // Collection of visual children + private readonly VisualCollection visualChildren; + + /// + /// Constructor + /// + /// Adorned element + /// Backstage + public BackstageAdorner(FrameworkElement adornedElement, Backstage backstage) + : base(adornedElement) + { + KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Cycle); + + this.Backstage = backstage; + this.backstageContent = this.Backstage.Content; + + this.visualChildren = new VisualCollection(this) + { + this.backstageContent + }; + + // TODO: fix it! (below ugly workaround) in measureoverride we cannot get RenderSize, we must use DesiredSize + // Syncronize with visual size + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + CompositionTarget.Rendering += this.CompositionTargetRendering; + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + CompositionTarget.Rendering -= this.CompositionTargetRendering; + } + + private void CompositionTargetRendering(object sender, EventArgs e) + { + if (this.RenderSize != this.AdornedElement.RenderSize) + { + this.InvalidateMeasure(); + } + } + + public void Clear() + { + this.visualChildren.Clear(); + } + + #region Layout & Visual Children + + /// + /// Positions child elements and determines + /// a size for the control + /// + /// The final area within the parent + /// that this element should use to arrange + /// itself and its children + /// The actual size used + protected override Size ArrangeOverride(Size finalSize) + { + this.backstageContent.Arrange(new Rect(0, 0, finalSize.Width, Math.Max(0, finalSize.Height))); + return finalSize; + } + + /// + /// Measures KeyTips + /// + /// The available size that this element can give to child elements. + /// The size that the groups container determines it needs during + /// layout, based on its calculations of child element sizes. + /// + protected override Size MeasureOverride(Size constraint) + { + // TODO: fix it! (below ugly workaround) in measureoverride we cannot get RenderSize, we must use DesiredSize + this.backstageContent.Measure(new Size(this.AdornedElement.RenderSize.Width, Math.Max(0, this.AdornedElement.RenderSize.Height))); + return this.AdornedElement.RenderSize; + } + + /// + /// Gets visual children count + /// + protected override int VisualChildrenCount { get { return this.visualChildren.Count; } } + + /// + /// Returns a child at the specified index from a collection of child elements + /// + /// The zero-based index of the requested child element in the collection + /// The requested child element + protected override Visual GetVisualChild(int index) { return this.visualChildren[index]; } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/BackstageTabControl.cs b/Fluent.Ribbon/Controls/BackstageTabControl.cs similarity index 58% rename from Fluent/Controls/BackstageTabControl.cs rename to Fluent.Ribbon/Controls/BackstageTabControl.cs index b3aaa3a2e..adcfaca33 100644 --- a/Fluent/Controls/BackstageTabControl.cs +++ b/Fluent.Ribbon/Controls/BackstageTabControl.cs @@ -1,451 +1,437 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents Backstage tab control. - /// - public class BackstageTabControl : Selector - { - #region Properties - - // Dependency property key for SelectedContent - private static readonly DependencyPropertyKey SelectedContentPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContent", typeof(object), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property SelectedContent - /// - public static readonly DependencyProperty SelectedContentProperty = SelectedContentPropertyKey.DependencyProperty; - - /// - /// Gets content for selected tab - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public object SelectedContent - { - get - { - return this.GetValue(SelectedContentProperty); - } - internal set - { - this.SetValue(SelectedContentPropertyKey, value); - } - } - - /// - /// Dependency property ContentStringFormat - /// - public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register("ContentStringFormat", typeof(string), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property ContentTemplate - /// - public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property ContentTemplateSelector - /// - public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register("ContentTemplateSelector", typeof(DataTemplateSelector), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - private static readonly DependencyPropertyKey SelectedContentStringFormatPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContentStringFormat", typeof(string), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property SelectedContentStringFormat - /// - public static readonly DependencyProperty SelectedContentStringFormatProperty = SelectedContentStringFormatPropertyKey.DependencyProperty; - - private static readonly DependencyPropertyKey SelectedContentTemplatePropertyKey = DependencyProperty.RegisterReadOnly("SelectedContentTemplate", typeof(DataTemplate), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property SelectedContentTemplate - /// - public static readonly DependencyProperty SelectedContentTemplateProperty = SelectedContentTemplatePropertyKey.DependencyProperty; - - private static readonly DependencyPropertyKey SelectedContentTemplateSelectorPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContentTemplateSelector", typeof(DataTemplateSelector), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Dependency property SelectedContentTemplateSelector - /// - public static readonly DependencyProperty SelectedContentTemplateSelectorProperty = SelectedContentTemplateSelectorPropertyKey.DependencyProperty; - - /// - /// Get or sets the string format for the content. - /// - public string ContentStringFormat - { - get - { - return (string)this.GetValue(ContentStringFormatProperty); - } - set - { - this.SetValue(ContentStringFormatProperty, value); - } - } - - /// - /// Gets or sets the which should be used for the content - /// - public DataTemplate ContentTemplate - { - get - { - return (DataTemplate)this.GetValue(ContentTemplateProperty); - } - set - { - this.SetValue(ContentTemplateProperty, value); - } - } - - /// - /// Gets or sets the which should be used for the content - /// - public DataTemplateSelector ContentTemplateSelector - { - get - { - return (DataTemplateSelector)this.GetValue(ContentTemplateSelectorProperty); - } - set - { - this.SetValue(ContentTemplateSelectorProperty, value); - } - } - - /// - /// Get or sets the string format for the selected content. - /// - public string SelectedContentStringFormat - { - get - { - return (string)this.GetValue(SelectedContentStringFormatProperty); - } - internal set - { - this.SetValue(SelectedContentStringFormatPropertyKey, value); - } - } - - /// - /// Gets or sets the which should be used for the selected content - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public DataTemplate SelectedContentTemplate - { - get - { - return (DataTemplate)this.GetValue(SelectedContentTemplateProperty); - } - internal set - { - this.SetValue(SelectedContentTemplatePropertyKey, value); - } - } - - /// - /// Gets or sets the which should be used for the selected content - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public DataTemplateSelector SelectedContentTemplateSelector - { - get - { - return (DataTemplateSelector)this.GetValue(SelectedContentTemplateSelectorProperty); - } - internal set - { - this.SetValue(SelectedContentTemplateSelectorPropertyKey, value); - } - } - - #region ItemsPanelBackground - - /// - /// Gets or sets current Backround of the ItemsPanel - /// - public Brush ItemsPanelBackground - { - get { return (Brush)this.GetValue(ItemsPanelBackgroundProperty); } - set { this.SetValue(ItemsPanelBackgroundProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Foreground. - /// This enables animation, styling, binding, etc... - /// - public static DependencyProperty ItemsPanelBackgroundProperty = - DependencyProperty.Register("ItemsPanelBackground", typeof(Brush), typeof(BackstageTabControl)); - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static BackstageTabControl() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(typeof(BackstageTabControl))); - StyleProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(BackstageTabControl)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public BackstageTabControl() - { - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - - // Fixed incoreect menu showing - this.ContextMenu = new ContextMenu - { - Width = 0, - Height = 0, - HasDropShadow = false - }; - this.ContextMenu.Opened += delegate { ContextMenu.IsOpen = false; }; - } - - #endregion - - #region Overrides - - /// - /// Raises the System.Windows.FrameworkElement.Initialized event. - /// This method is invoked whenever System.Windows.FrameworkElement. - /// IsInitialized is set to true internally. - /// - /// The System.Windows.RoutedEventArgs that contains the event data. - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - this.ItemContainerGenerator.StatusChanged += this.OnGeneratorStatusChanged; - } - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new BackstageTabItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is BackstageTabItem - || item is Button - || item is SeparatorTabItem - || item is Separator; - } - - /// - /// Updates the current selection when an item in the System.Windows.Controls.Primitives.Selector has changed - /// - /// The event data. - protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) - { - base.OnItemsChanged(e); - - if ((e.Action == NotifyCollectionChangedAction.Remove) && (this.SelectedIndex == -1)) - { - var startIndex = e.OldStartingIndex + 1; - if (startIndex > this.Items.Count) - { - startIndex = 0; - } - - var item = this.FindNextTabItem(startIndex, -1); - if (item != null) - { - item.IsSelected = true; - } - } - } - - /// - /// Called when the selection changes. - /// - /// The event data. - protected override void OnSelectionChanged(SelectionChangedEventArgs e) - { - base.OnSelectionChanged(e); - if (e.AddedItems.Count > 0) - { - this.UpdateSelectedContent(); - } - e.Handled = true; - } - - /// - /// Invoked when an unhandled MouseLeftButtonDown routed event - /// is raised on this element. Implement this method to add class handling for this event. - /// - /// The MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - base.OnMouseLeftButtonDown(e); - e.Handled = true; - } - - #endregion - - #region Private methods - - // Gets selected ribbon tab item - BackstageTabItem GetSelectedTabItem() - { - object selectedItem = this.SelectedItem; - if (selectedItem == null) - { - return null; - } - BackstageTabItem item = selectedItem as BackstageTabItem; - if (item == null) - { - item = this.FindNextTabItem(this.SelectedIndex, 1); - this.SelectedItem = item; - } - return item; - } - - // Finds next tab item - private BackstageTabItem FindNextTabItem(int startIndex, int direction) - { - if (direction != 0) - { - int index = startIndex; - for (int i = 0; i < this.Items.Count; i++) - { - index += direction; - if (index >= this.Items.Count) - { - index = 0; - } - else if (index < 0) - { - index = this.Items.Count - 1; - } - BackstageTabItem item2 = this.ItemContainerGenerator.ContainerFromIndex(index) as BackstageTabItem; - if (((item2 != null) && item2.IsEnabled) && (item2.Visibility == Visibility.Visible)) - { - return item2; - } - } - } - return null; - } - - // Updates selected content - private void UpdateSelectedContent() - { - if (this.SelectedIndex < 0) - { - - this.SelectedContent = null; - } - else - { - BackstageTabItem selectedTabItem = this.GetSelectedTabItem(); - if (selectedTabItem != null) - { - this.SelectedContent = selectedTabItem.Content; - if (((selectedTabItem.ContentTemplate != null) || (selectedTabItem.ContentTemplateSelector != null)) || (selectedTabItem.ContentStringFormat != null)) - { - this.SelectedContentTemplate = selectedTabItem.ContentTemplate; - this.SelectedContentTemplateSelector = selectedTabItem.ContentTemplateSelector; - this.SelectedContentStringFormat = selectedTabItem.ContentStringFormat; - } - else - { - this.SelectedContentTemplate = this.ContentTemplate; - this.SelectedContentTemplateSelector = this.ContentTemplateSelector; - this.SelectedContentStringFormat = this.ContentStringFormat; - } - - this.UpdateLayout(); - } - } - } - - #endregion - - #region Event handling - - // Handles GeneratorStatusChange - private void OnGeneratorStatusChanged(object sender, EventArgs e) - { - if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) - { - if (this.HasItems && (this.SelectedIndex == -1)) - { - this.SelectedIndex = 0; - } - this.UpdateSelectedContent(); - } - } - - private void OnPopupDismiss(object sender, DismissPopupEventArgs e) - { - var backstage = LogicalTreeHelper.GetParent(this); - - if (backstage != null) - { - PopupService.RaiseDismissPopupEvent(backstage, DismissPopupMode.Always); - } - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.AddHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.RemoveHandler(PopupService.DismissPopupEvent, (DismissPopupEventHandler)this.OnPopupDismiss); - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Media; + using Fluent.Internal; + + /// + /// Represents Backstage tab control. + /// + public class BackstageTabControl : Selector + { + #region Properties + + // Dependency property key for SelectedContent + private static readonly DependencyPropertyKey SelectedContentPropertyKey = DependencyProperty.RegisterReadOnly(nameof(SelectedContent), typeof(object), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty SelectedContentProperty = SelectedContentPropertyKey.DependencyProperty; + + /// + /// Gets content for selected tab + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object SelectedContent + { + get + { + return this.GetValue(SelectedContentProperty); + } + internal set + { + this.SetValue(SelectedContentPropertyKey, value); + } + } + + /// + /// Dependency property for + /// + public static readonly DependencyProperty ContentStringFormatProperty = DependencyProperty.Register(nameof(ContentStringFormat), typeof(string), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register(nameof(ContentTemplateSelector), typeof(DataTemplateSelector), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + private static readonly DependencyPropertyKey SelectedContentStringFormatPropertyKey = DependencyProperty.RegisterReadOnly(nameof(SelectedContentStringFormat), typeof(string), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty SelectedContentStringFormatProperty = SelectedContentStringFormatPropertyKey.DependencyProperty; + + private static readonly DependencyPropertyKey SelectedContentTemplatePropertyKey = DependencyProperty.RegisterReadOnly(nameof(SelectedContentTemplate), typeof(DataTemplate), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty SelectedContentTemplateProperty = SelectedContentTemplatePropertyKey.DependencyProperty; + + private static readonly DependencyPropertyKey SelectedContentTemplateSelectorPropertyKey = DependencyProperty.RegisterReadOnly(nameof(SelectedContentTemplateSelector), typeof(DataTemplateSelector), typeof(BackstageTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Dependency property for + /// + public static readonly DependencyProperty SelectedContentTemplateSelectorProperty = SelectedContentTemplateSelectorPropertyKey.DependencyProperty; + + /// + /// Get or sets the string format for the content. + /// + public string ContentStringFormat + { + get + { + return (string)this.GetValue(ContentStringFormatProperty); + } + set + { + this.SetValue(ContentStringFormatProperty, value); + } + } + + /// + /// Gets or sets the which should be used for the content + /// + public DataTemplate ContentTemplate + { + get + { + return (DataTemplate)this.GetValue(ContentTemplateProperty); + } + set + { + this.SetValue(ContentTemplateProperty, value); + } + } + + /// + /// Gets or sets the which should be used for the content + /// + public DataTemplateSelector ContentTemplateSelector + { + get + { + return (DataTemplateSelector)this.GetValue(ContentTemplateSelectorProperty); + } + set + { + this.SetValue(ContentTemplateSelectorProperty, value); + } + } + + /// + /// Get or sets the string format for the selected content. + /// + public string SelectedContentStringFormat + { + get + { + return (string)this.GetValue(SelectedContentStringFormatProperty); + } + internal set + { + this.SetValue(SelectedContentStringFormatPropertyKey, value); + } + } + + /// + /// Gets or sets the which should be used for the selected content + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DataTemplate SelectedContentTemplate + { + get + { + return (DataTemplate)this.GetValue(SelectedContentTemplateProperty); + } + internal set + { + this.SetValue(SelectedContentTemplatePropertyKey, value); + } + } + + /// + /// Gets or sets the which should be used for the selected content + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public DataTemplateSelector SelectedContentTemplateSelector + { + get + { + return (DataTemplateSelector)this.GetValue(SelectedContentTemplateSelectorProperty); + } + internal set + { + this.SetValue(SelectedContentTemplateSelectorPropertyKey, value); + } + } + + #region ItemsPanelBackground + + /// + /// Gets or sets current Backround of the ItemsPanel + /// + public Brush ItemsPanelBackground + { + get { return (Brush)this.GetValue(ItemsPanelBackgroundProperty); } + set { this.SetValue(ItemsPanelBackgroundProperty, value); } + } + + /// + /// Dependency property for + /// + public static DependencyProperty ItemsPanelBackgroundProperty = + DependencyProperty.Register(nameof(ItemsPanelBackground), typeof(Brush), typeof(BackstageTabControl)); + + #endregion + + /// + /// Gets or sets the + /// + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Backstage ParentBackstage + { + get { return (Backstage)this.GetValue(ParentBackstageProperty); } + set { this.SetValue(ParentBackstageProperty, value); } + } + + /// + /// for + /// + public static readonly DependencyProperty ParentBackstageProperty = + DependencyProperty.Register(nameof(ParentBackstage), typeof(Backstage), typeof(BackstageTabControl), new PropertyMetadata(null)); + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static BackstageTabControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(typeof(BackstageTabControl))); + } + + /// + /// Default constructor + /// + public BackstageTabControl() + { + // Fixed incorect menu showing + this.ContextMenu = new ContextMenu + { + Width = 0, + Height = 0, + HasDropShadow = false + }; + this.ContextMenu.Opened += delegate { this.ContextMenu.IsOpen = false; }; + + this.Loaded += this.HandleLoaded; + this.Unloaded += this.HandleUnloaded; + } + + private void HandleLoaded(object sender, RoutedEventArgs e) + { + this.ParentBackstage = UIHelper.GetParent(this); + } + + private void HandleUnloaded(object sender, RoutedEventArgs e) + { + this.ParentBackstage = null; + } + + #endregion + + #region Overrides + + /// + /// Raises the System.Windows.FrameworkElement.Initialized event. + /// This method is invoked whenever System.Windows.FrameworkElement. + /// IsInitialized is set to true internally. + /// + /// The System.Windows.RoutedEventArgs that contains the event data. + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + this.ItemContainerGenerator.StatusChanged += this.OnGeneratorStatusChanged; + } + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new BackstageTabItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is BackstageTabItem + || item is Button + || item is SeparatorTabItem + || item is Separator; + } + + /// + /// Updates the current selection when an item in the System.Windows.Controls.Primitives.Selector has changed + /// + /// The event data. + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (e.Action == NotifyCollectionChangedAction.Remove + && this.SelectedIndex == -1) + { + var startIndex = e.OldStartingIndex + 1; + if (startIndex > this.Items.Count) + { + startIndex = 0; + } + + var item = this.FindNextTabItem(startIndex, -1); + if (item != null) + { + item.IsSelected = true; + } + } + } + + /// + /// Called when the selection changes. + /// + /// The event data. + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + base.OnSelectionChanged(e); + + if (e.AddedItems.Count > 0) + { + this.UpdateSelectedContent(); + } + } + + #endregion + + #region Private methods + + // Gets selected ribbon tab item + private BackstageTabItem GetSelectedTabItem() + { + var container = this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as BackstageTabItem; + if (container == null) + { + container = this.FindNextTabItem(this.SelectedIndex, 1); + this.SelectedItem = this.ItemContainerGenerator.ItemFromContainer(container); + } + + return container; + } + + // Finds next tab item + private BackstageTabItem FindNextTabItem(int startIndex, int direction) + { + if (direction == 0) + { + return null; + } + + var index = startIndex; + for (var i = 0; i < this.Items.Count; i++) + { + index += direction; + + if (index >= this.Items.Count) + { + index = 0; + } + else if (index < 0) + { + index = this.Items.Count - 1; + } + + var container = this.ItemContainerGenerator.ContainerFromIndex(index) as BackstageTabItem; + + if (container != null + && container.IsEnabled + && container.Visibility == Visibility.Visible) + { + return container; + } + } + + return null; + } + + // Updates selected content + private void UpdateSelectedContent() + { + if (this.SelectedIndex < 0) + { + this.SelectedContent = null; + } + else + { + var selectedTabItem = this.GetSelectedTabItem(); + if (selectedTabItem == null) + { + return; + } + + this.SelectedContent = selectedTabItem.Content; + if (selectedTabItem.ContentTemplate != null + || selectedTabItem.ContentTemplateSelector != null + || selectedTabItem.ContentStringFormat != null) + { + this.SelectedContentTemplate = selectedTabItem.ContentTemplate; + this.SelectedContentTemplateSelector = selectedTabItem.ContentTemplateSelector; + this.SelectedContentStringFormat = selectedTabItem.ContentStringFormat; + } + else + { + this.SelectedContentTemplate = this.ContentTemplate; + this.SelectedContentTemplateSelector = this.ContentTemplateSelector; + this.SelectedContentStringFormat = this.ContentStringFormat; + } + + this.UpdateLayout(); + } + } + + #endregion + + #region Event handling + + // Handles GeneratorStatusChange + private void OnGeneratorStatusChanged(object sender, EventArgs e) + { + if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) + { + return; + } + + if (this.HasItems + && this.SelectedIndex == -1) + { + this.SelectedIndex = 0; + } + + this.UpdateSelectedContent(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/BackstageTabItem.cs b/Fluent.Ribbon/Controls/BackstageTabItem.cs similarity index 64% rename from Fluent/Controls/BackstageTabItem.cs rename to Fluent.Ribbon/Controls/BackstageTabItem.cs index 0c2d80ac9..0826f74b4 100644 --- a/Fluent/Controls/BackstageTabItem.cs +++ b/Fluent.Ribbon/Controls/BackstageTabItem.cs @@ -1,248 +1,220 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; - -namespace Fluent -{ - /// - /// Represents backstage tab item - /// - public class BackstageTabItem : ContentControl, IKeyTipedControl - { - #region Properties - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(BackstageTabItem)); - - #endregion - - /// - /// Dependency property for isSelected - /// - public static readonly DependencyProperty IsSelectedProperty = - Selector.IsSelectedProperty.AddOwner(typeof(BackstageTabItem), - new FrameworkPropertyMetadata(false, - FrameworkPropertyMetadataOptions.Journal | - FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | - FrameworkPropertyMetadataOptions.AffectsParentMeasure, - OnIsSelectedChanged)); - - /// - /// Gets or sets whether the tab is selected - /// - [Bindable(true), Category("Appearance")] - public bool IsSelected - { - get - { - return (bool)this.GetValue(IsSelectedProperty); - } - set - { - this.SetValue(IsSelectedProperty, value); - } - } - - /// - /// Gets parent tab control - /// - internal BackstageTabControl TabControlParent - { - get - { - return (ItemsControl.ItemsControlFromItemContainer(this) as BackstageTabControl); - } - } - - /// - /// Gets or sets tab items text - /// - public object Header - { - get { return this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Text. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(BackstageTabItem), new PropertyMetadata(null)); - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static BackstageTabItem() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageTabItem), - new FrameworkPropertyMetadata(typeof(BackstageTabItem))); - StyleProperty.OverrideMetadata(typeof(BackstageTabItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(BackstageTabItem)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public BackstageTabItem() - { - - } - - #endregion - - #region Overrides - - /// - /// Called when the System.Windows.Controls.ContentControl.Content property changes. - /// - /// The old value of the System.Windows.Controls.ContentControl.Content property. - /// The new value of the System.Windows.Controls.ContentControl.Content property. - protected override void OnContentChanged(object oldContent, object newContent) - { - base.OnContentChanged(oldContent, newContent); - if (this.IsSelected && - this.TabControlParent != null) - { - this.TabControlParent.SelectedContent = newContent; - } - } - - /// - /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonDownrouted event is raised on this element. - /// Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - if (((e.Source == this) || !this.IsSelected)) - { - if (this.TabControlParent != null && - this.TabControlParent.SelectedItem is BackstageTabItem) - ((BackstageTabItem)this.TabControlParent.SelectedItem).IsSelected = false; - - this.IsSelected = true; - } - e.Handled = true; - } - - #endregion - - #region Private methods - - // Handles IsSelected changed - private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - BackstageTabItem container = (BackstageTabItem)d; - bool newValue = (bool)e.NewValue; - - if (newValue) - { - BackstageTabControl backstage = container.Parent as BackstageTabControl; - if ((backstage != null) && (backstage.SelectedItem != container)) - { - if (backstage.SelectedItem is BackstageTabItem) (backstage.SelectedItem as BackstageTabItem).IsSelected = false; - backstage.SelectedItem = container; - } - container.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, container)); - } - else - { - container.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, container)); - } - } - - /// - /// Handles selected event - /// - /// The event data. - protected virtual void OnSelected(RoutedEventArgs e) - { - this.HandleIsSelectedChanged(e); - } - - /// - /// Handles unselected event - /// - /// The event data. - protected virtual void OnUnselected(RoutedEventArgs e) - { - this.HandleIsSelectedChanged(e); - } - - #endregion - - #region Event handling - - /// - /// Handles IsSelected changed - /// - /// The event data. - private void HandleIsSelectedChanged(RoutedEventArgs e) - { - this.RaiseEvent(e); - } - - #endregion - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - if (this.TabControlParent != null && - this.TabControlParent.SelectedItem is RibbonTabItem) - ((BackstageTabItem)this.TabControlParent.SelectedItem).IsSelected = false; - - this.IsSelected = true; - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - } -} +namespace Fluent +{ + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Input; + + /// + /// Represents backstage tab item + /// + public class BackstageTabItem : ContentControl, IKeyTipedControl + { + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Dependency property for + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(BackstageTabItem)); + + /// + /// Gets or sets whether the tab is selected + /// + [Bindable(true)] + [Category("Appearance")] + public bool IsSelected + { + get + { + return (bool)this.GetValue(IsSelectedProperty); + } + set + { + this.SetValue(IsSelectedProperty, value); + } + } + + /// + /// Dependency property for + /// + public static readonly DependencyProperty IsSelectedProperty = + Selector.IsSelectedProperty.AddOwner(typeof(BackstageTabItem), + new FrameworkPropertyMetadata(false, + FrameworkPropertyMetadataOptions.Journal | + FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | + FrameworkPropertyMetadataOptions.AffectsParentMeasure, + OnIsSelectedChanged)); + + /// + /// Gets parent tab control + /// + internal BackstageTabControl TabControlParent + { + get + { + return ItemsControl.ItemsControlFromItemContainer(this) as BackstageTabControl; + } + } + + /// + /// Gets or sets tab items text + /// + public object Header + { + get { return this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Text. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(object), typeof(BackstageTabItem), new PropertyMetadata(null)); + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static BackstageTabItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageTabItem), new FrameworkPropertyMetadata(typeof(BackstageTabItem))); + } + + #region Overrides + + /// + /// Called when the System.Windows.Controls.ContentControl.Content property changes. + /// + /// The old value of the System.Windows.Controls.ContentControl.Content property. + /// The new value of the System.Windows.Controls.ContentControl.Content property. + protected override void OnContentChanged(object oldContent, object newContent) + { + base.OnContentChanged(oldContent, newContent); + + if (this.IsSelected + && this.TabControlParent != null) + { + this.TabControlParent.SelectedContent = newContent; + } + } + + /// + /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonDownrouted event is raised on this element. + /// Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + if (ReferenceEquals(e.Source, this) + || this.IsSelected == false) + { + this.IsSelected = true; + } + } + + #endregion + + #region Private methods + + // Handles IsSelected changed + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var container = (BackstageTabItem)d; + var newValue = (bool)e.NewValue; + + var backstageTabControl = container.Parent as BackstageTabControl; + + if (newValue) + { + if (backstageTabControl != null + && ReferenceEquals(backstageTabControl.ItemContainerGenerator.ContainerFromItem(backstageTabControl.SelectedItem), container) == false) + { + UnselectSelectedItem(backstageTabControl); + + backstageTabControl.SelectedItem = backstageTabControl.ItemContainerGenerator.ItemFromContainer(container); + } + + container.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, container)); + } + else + { + container.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, container)); + } + } + + private static void UnselectSelectedItem(BackstageTabControl backstageTabControl) + { + if (backstageTabControl?.SelectedItem == null) + { + return; + } + + var backstageTabItem = backstageTabControl.ItemContainerGenerator.ContainerFromItem(backstageTabControl.SelectedItem) as BackstageTabItem; + + if (backstageTabItem != null) + { + backstageTabItem.IsSelected = false; + } + } + + #endregion + + /// + /// Handles selected event + /// + /// The event data. + protected virtual void OnSelected(RoutedEventArgs e) + { + this.HandleIsSelectedChanged(e); + } + + /// + /// Handles unselected event + /// + /// The event data. + protected virtual void OnUnselected(RoutedEventArgs e) + { + this.HandleIsSelectedChanged(e); + } + + #region Event handling + + /// + /// Handles IsSelected changed + /// + /// The event data. + private void HandleIsSelectedChanged(RoutedEventArgs e) + { + this.RaiseEvent(e); + } + + #endregion + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + UnselectSelectedItem(this.TabControlParent); + + this.IsSelected = true; + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + } +} \ No newline at end of file diff --git a/Fluent/Controls/Button.cs b/Fluent.Ribbon/Controls/Button.cs similarity index 93% rename from Fluent/Controls/Button.cs rename to Fluent.Ribbon/Controls/Button.cs index 9957f4b56..cdfb2313e 100644 --- a/Fluent/Controls/Button.cs +++ b/Fluent.Ribbon/Controls/Button.cs @@ -1,293 +1,284 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represents button - /// - [ContentProperty("Header")] - public class Button : System.Windows.Controls.Button, IRibbonControl, IQuickAccessItemProvider - { - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(Button)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(Button)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(Button)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (object)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(Button), new PropertyMetadata(null)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(Button), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - Button element = d as Button; - FrameworkElement oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - FrameworkElement newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - #endregion - - #region LargeIcon - - /// - /// Gets or sets button large icon - /// - public object LargeIcon - { - get { return this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(object), - typeof(Button), new FrameworkPropertyMetadata(null, null)); - - #endregion - - #region IsDefinitive - - /// - /// Gets or sets whether ribbon control click must close backstage - /// - public bool IsDefinitive - { - get { return (bool)this.GetValue(IsDefinitiveProperty); } - set { this.SetValue(IsDefinitiveProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDefinitiveProperty = - DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(Button), new UIPropertyMetadata(true)); - - #endregion - - #region CornerRadius - - /// - /// Gets or sets the CornerRadius for the element - /// - public CornerRadius CornerRadius - { - get { return (CornerRadius)this.GetValue(CornerRadiusProperty); } - set { this.SetValue(CornerRadiusProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CornerRadiusProperty = - DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Button), new PropertyMetadata(default(CornerRadius))); - - #endregion CornerRadius - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static Button() - { - Type type = typeof(Button); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - ContextMenuService.Attach(type); - ToolTipService.Attach(type); - StyleProperty.OverrideMetadata(typeof(Button), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(Button)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public Button() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region Overrides - - /// - /// Called when a is clicked. - /// - protected override void OnClick() - { - // Close popup on click - if (this.IsDefinitive) - { - PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); - } - - base.OnClick(); - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be synchronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - Button button = new Button(); - button.Click += ((sender, e) => this.RaiseEvent(e)); - RibbonControl.BindQuickAccessItem(this, button); - return button; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(Button), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IKeyTipedControl - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.OnClick(); - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - } +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents button + /// + [ContentProperty("Header")] + public class Button : System.Windows.Controls.Button, IRibbonControl, IQuickAccessItemProvider + { + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(Button)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(Button)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(Button)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (object)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(Button), new PropertyMetadata(null)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(Button), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + Button element = d as Button; + FrameworkElement oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) element.RemoveLogicalChild(oldElement); + FrameworkElement newElement = e.NewValue as FrameworkElement; + if (newElement != null) element.AddLogicalChild(newElement); + } + #endregion + + #region LargeIcon + + /// + /// Gets or sets button large icon + /// + public object LargeIcon + { + get { return this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = + DependencyProperty.Register("LargeIcon", typeof(object), + typeof(Button), new FrameworkPropertyMetadata(null, null)); + + #endregion + + #region IsDefinitive + + /// + /// Gets or sets whether ribbon control click must close backstage + /// + public bool IsDefinitive + { + get { return (bool)this.GetValue(IsDefinitiveProperty); } + set { this.SetValue(IsDefinitiveProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDefinitiveProperty = + DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(Button), new UIPropertyMetadata(true)); + + #endregion + + #region CornerRadius + + /// + /// Gets or sets the CornerRadius for the element + /// + public CornerRadius CornerRadius + { + get { return (CornerRadius)this.GetValue(CornerRadiusProperty); } + set { this.SetValue(CornerRadiusProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CornerRadiusProperty = + DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Button), new PropertyMetadata(default(CornerRadius))); + + #endregion CornerRadius + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static Button() + { + Type type = typeof(Button); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + ContextMenuService.Attach(type); + ToolTipService.Attach(type); + StyleProperty.OverrideMetadata(typeof(Button), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(Button)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public Button() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region Overrides + + /// + /// Called when a is clicked. + /// + protected override void OnClick() + { + // Close popup on click + if (this.IsDefinitive) + { + PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); + } + + base.OnClick(); + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be synchronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + Button button = new Button(); + button.Click += ((sender, e) => this.RaiseEvent(e)); + RibbonControl.BindQuickAccessItem(this, button); + return button; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(Button), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IKeyTipedControl + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.OnClick(); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/CheckBox.cs b/Fluent.Ribbon/Controls/CheckBox.cs similarity index 89% rename from Fluent/Controls/CheckBox.cs rename to Fluent.Ribbon/Controls/CheckBox.cs index 09d80f7e2..6d487bb9e 100644 --- a/Fluent/Controls/CheckBox.cs +++ b/Fluent.Ribbon/Controls/CheckBox.cs @@ -1,244 +1,232 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents Fluent UI specific CheckBox - /// - [ContentProperty("Header")] - public class CheckBox : System.Windows.Controls.CheckBox, IRibbonControl, IQuickAccessItemProvider - { - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(CheckBox)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(CheckBox)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(CheckBox)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(CheckBox)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(CheckBox), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - CheckBox element = d as CheckBox; - FrameworkElement oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - FrameworkElement newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - - #endregion - - #region LargeIcon - - /// - /// Gets or sets button large icon - /// - public ImageSource LargeIcon - { - get { return (ImageSource)this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(ImageSource), - typeof(CheckBox), new UIPropertyMetadata(null)); - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static CheckBox() - { - Type type = typeof(CheckBox); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - ContextMenuService.Attach(type); - ToolTipService.Attach(type); - StyleProperty.OverrideMetadata(typeof(CheckBox), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(CheckBox)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public CheckBox() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - CheckBox button = new CheckBox(); - - RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); - button.Click += ((sender, e) => this.RaiseEvent(e)); - RibbonControl.BindQuickAccessItem(this, button); - - return button; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(CheckBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IKeyTipedControl - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.OnClick(); - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents Fluent UI specific CheckBox + /// + [ContentProperty("Header")] + public class CheckBox : System.Windows.Controls.CheckBox, IRibbonControl, IQuickAccessItemProvider + { + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(CheckBox)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(CheckBox)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(CheckBox)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(CheckBox)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(CheckBox), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + CheckBox element = d as CheckBox; + FrameworkElement oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) element.RemoveLogicalChild(oldElement); + FrameworkElement newElement = e.NewValue as FrameworkElement; + if (newElement != null) element.AddLogicalChild(newElement); + } + + #endregion + + #region LargeIcon + + /// + /// Gets or sets button large icon + /// + public object LargeIcon + { + get { return this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = DependencyProperty.Register("LargeIcon", typeof(object), typeof(CheckBox), new UIPropertyMetadata(null)); + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static CheckBox() + { + Type type = typeof(CheckBox); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + ContextMenuService.Attach(type); + ToolTipService.Attach(type); + StyleProperty.OverrideMetadata(typeof(CheckBox), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(CheckBox)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public CheckBox() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + CheckBox button = new CheckBox(); + + RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); + button.Click += ((sender, e) => this.RaiseEvent(e)); + RibbonControl.BindQuickAccessItem(this, button); + + return button; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(CheckBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IKeyTipedControl + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.OnClick(); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/ColorGallery.cs b/Fluent.Ribbon/Controls/ColorGallery.cs similarity index 97% rename from Fluent/Controls/ColorGallery.cs rename to Fluent.Ribbon/Controls/ColorGallery.cs index de4743448..cb077349a 100644 --- a/Fluent/Controls/ColorGallery.cs +++ b/Fluent.Ribbon/Controls/ColorGallery.cs @@ -1,1074 +1,1074 @@ -namespace Fluent -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.Diagnostics; - using System.Runtime.InteropServices; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Interop; - using System.Windows.Markup; - using System.Windows.Media; - using System.Windows.Threading; - - /// - /// Represents color gallery modes - /// - public enum ColorGalleryMode - { - /// - /// Color gallery displays only fixed highlight colors - /// - HighlightColors = 0, - - /// - /// Color gallery displays only fixed standart colors - /// - StandardColors, - - /// - /// Color gallery displays theme colors - /// - ThemeColors - } - - /// - /// Date template selector for gradients - /// - public class ColorGradientItemTemplateSelector : DataTemplateSelector - { - /// - /// When overridden in a derived class, returns a based on custom logic. - /// - /// - /// Returns a or null. The default value is null. - /// - /// The data object for which to select the template.The data-bound object. - public override DataTemplate SelectTemplate(object item, DependencyObject container) - { - if (item == null) - { - return null; - } - - ListBox listBox = null; - var parent = container; - while (parent != null) - { - parent = VisualTreeHelper.GetParent(parent); - listBox = parent as ListBox; - if (listBox != null) - { - break; - } - } - - if (listBox == null) - { - return null; - } - - ColorGallery colorGallery = null; - while (parent != null) - { - parent = VisualTreeHelper.GetParent(parent); - colorGallery = parent as ColorGallery; - if (colorGallery != null) break; - } - - if (colorGallery == null) - { - return null; - } - - var index = listBox.Items.IndexOf(item); - if (index < colorGallery.Columns) - { - return listBox.TryFindResource("GradientColorTopDataTemplate") as DataTemplate; - } - - if (index >= listBox.Items.Count - colorGallery.Columns) - { - return listBox.TryFindResource("GradientColorBottomDataTemplate") as DataTemplate; - } - - return listBox.TryFindResource("GradientColorCenterDataTemplate") as DataTemplate; - } - - } - - /// - /// More colors event args - /// - public class MoreColorsExecutingEventArgs : EventArgs - { - /// - /// Gets or sets choosed color - /// - public Color Color { get; set; } - /// - /// Gets or sets a value indicating whether more colors is canceled - /// - public bool Canceled { get; set; } - } - - /// - /// Represents color gallery - /// - [ContentProperty("ThemeColors")] - public class ColorGallery : Control - { - #region Constants - - /// - /// Hightlight colors array - /// - public static readonly Color[] HighlightColors = new Color[] - { - Color.FromRgb(0xFF ,0xFF ,0x00), - Color.FromRgb(0x00 ,0xFF ,0x00), - Color.FromRgb(0x00 ,0xFF ,0xFF), - - Color.FromRgb(0xFF ,0x00 ,0xFF), - Color.FromRgb(0x00 ,0x00 ,0xFF), - Color.FromRgb(0xFF ,0x00 ,0x00), - - Color.FromRgb(0x00 ,0x00 ,0x80), - Color.FromRgb(0x00 ,0x80 ,0x80), - Color.FromRgb(0x00 ,0x80 ,0x00), - - Color.FromRgb(0x80 ,0x00 ,0x80), - Color.FromRgb(0x80 ,0x00 ,0x00), - Color.FromRgb(0x80 ,0x80 ,0x00), - - Color.FromRgb(0x80 ,0x80 ,0x80), - Color.FromRgb(0xC0 ,0xC0 ,0xC0), - Color.FromRgb(0x00 ,0x00 ,0x00), - }; - - /// - /// Standard colors array - /// - public static readonly Color[] StandardColors = new Color[] - { - Color.FromRgb(0xFF ,0xFF ,0xFF), - Color.FromRgb(0xFF ,0x00 ,0x00), - Color.FromRgb(0xC0 ,0x50 ,0x4D), - Color.FromRgb(0xD1 ,0x63 ,0x49), - Color.FromRgb(0xDD ,0x84 ,0x84), - - Color.FromRgb(0xCC ,0xCC ,0xCC), - Color.FromRgb(0xFF ,0xC0 ,0x00), - Color.FromRgb(0xF7 ,0x96 ,0x46), - Color.FromRgb(0xD1 ,0x90 ,0x49), - Color.FromRgb(0xF3 ,0xA4 ,0x47), - - Color.FromRgb(0xA5 ,0xA5 ,0xA5), - Color.FromRgb(0xFF ,0xFF ,0x00), - Color.FromRgb(0x9B ,0xBB ,0x59), - Color.FromRgb(0xCC ,0xB4 ,0x00), - Color.FromRgb(0xDF ,0xCE ,0x04), - - Color.FromRgb(0x66 ,0x66 ,0x66), - Color.FromRgb(0x00 ,0xB0 ,0x50), - Color.FromRgb(0x4B ,0xAC ,0xC6), - Color.FromRgb(0x8F ,0xB0 ,0x8C), - Color.FromRgb(0xA5 ,0xB5 ,0x92), - - Color.FromRgb(0x33 ,0x33 ,0x33), - Color.FromRgb(0x00 ,0x4D ,0xBB), - Color.FromRgb(0x4F ,0x81 ,0xBD), - Color.FromRgb(0x64 ,0x6B ,0x86), - Color.FromRgb(0x80 ,0x9E ,0xC2), - - Color.FromRgb(0x00 ,0x00 ,0x00), - Color.FromRgb(0x9B ,0x00 ,0xD3), - Color.FromRgb(0x80 ,0x64 ,0xA2), - Color.FromRgb(0x9E ,0x7C ,0x7C), - Color.FromRgb(0x9C ,0x85 ,0xC0), - }; - - /// - /// Standard colors array in ThemeColor mode - /// - public static readonly Color[] StandardThemeColors = new Color[] - { - Color.FromRgb(0xC0 ,0x00 ,0x00), - Color.FromRgb(0xFF ,0x00 ,0x00), - Color.FromRgb(0xFF ,0xC0 ,0x00), - Color.FromRgb(0xFF ,0xFF ,0x00), - Color.FromRgb(0x92 ,0xD0 ,0x50), - Color.FromRgb(0x00 ,0xB0 ,0x50), - Color.FromRgb(0x00 ,0xB0 ,0xF0), - Color.FromRgb(0x00 ,0x70 ,0xC0), - Color.FromRgb(0x00 ,0x20 ,0x60), - Color.FromRgb(0x70 ,0x30 ,0xA0), - }; - - #endregion - - #region RecentItems - - private static ObservableCollection recentColors; - - /// - /// Gets recent colors collection - /// - public static ObservableCollection RecentColors - { - get - { - if (recentColors == null) recentColors = new ObservableCollection(); - return recentColors; - } - } - - #endregion - - #region Fields - - private MenuItem noColorButton; - private MenuItem automaticButton; - - private MenuItem moreColorsButton; - - private ListBox themeColorsListBox; - private ListBox themeGradientsListBox; - private ListBox standardColorsListBox; - private ListBox standardGradientsListBox; - private ListBox recentColorsListBox; - - private readonly List listBoxes = new List(); - - private bool isSelectionChanging; - - private bool isTemplateApplied; - - - #endregion - - #region Properties - - #region Mode - - /// - /// Gets or sets color gallery mode - /// - public ColorGalleryMode Mode - { - get { return (ColorGalleryMode)this.GetValue(ModeProperty); } - set { this.SetValue(ModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ModeProperty = - DependencyProperty.Register("Mode", typeof(ColorGalleryMode), typeof(ColorGallery), new UIPropertyMetadata(ColorGalleryMode.StandardColors, OnModeChanged)); - - private static void OnModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as ColorGallery).UpdateGradients(); - } - - #endregion - - #region Chip Size - - /// - /// Gets or sets chip width - /// - public double ChipWidth - { - get { return (double)this.GetValue(ChipWidthProperty); } - set { this.SetValue(ChipWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ChipWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ChipWidthProperty = - DependencyProperty.Register("ChipWidth", typeof(double), typeof(ColorGallery), new UIPropertyMetadata(13.0, null, CoerceChipSize)); - - private static object CoerceChipSize(DependencyObject d, object basevalue) - { - double value = (double)basevalue; - if (value < 0) return 0; - return basevalue; - } - - /// - /// Gets or sets chip height - /// - public double ChipHeight - { - get { return (double)this.GetValue(ChipHeightProperty); } - set { this.SetValue(ChipHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ChipHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ChipHeightProperty = - DependencyProperty.Register("ChipHeight", typeof(double), typeof(ColorGallery), new UIPropertyMetadata(13.0, null, CoerceChipSize)); - - #endregion - - #region IsAutomaticColorButtonVisible - - /// - /// Gets or sets a value indicating whether Automatic button is visible - /// - public bool IsAutomaticColorButtonVisible - { - get { return (bool)this.GetValue(IsAutomaticColorButtonVisibleProperty); } - set { this.SetValue(IsAutomaticColorButtonVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsAutomaticColorButtonVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsAutomaticColorButtonVisibleProperty = - DependencyProperty.Register("IsAutomaticColorButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); - - #endregion - - #region IsNoColorButtonVisible - - /// - /// Gets or sets a value indicating whether No color button is visible - /// - public bool IsNoColorButtonVisible - { - get { return (bool)this.GetValue(IsNoColorButtonVisibleProperty); } - set { this.SetValue(IsNoColorButtonVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsNoColorButtonVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsNoColorButtonVisibleProperty = - DependencyProperty.Register("IsNoColorButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); - - #endregion - - #region IsMoreColorsButtonVisible - - /// - /// Gets or sets a value indicating whether More Colors button is visible - /// - public bool IsMoreColorsButtonVisible - { - get { return (bool)this.GetValue(IsMoreColorsButtonVisibleProperty); } - set { this.SetValue(IsMoreColorsButtonVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsMoreColorsButtonVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsMoreColorsButtonVisibleProperty = - DependencyProperty.Register("IsMoreColorsButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); - - #endregion - - #region IsRecentColorsVisible - - /// - /// Gets or set a value indicating whether recent colors group displayed. Work only when Mode is ThemeColors - /// - public bool IsRecentColorsVisible - { - get { return (bool)this.GetValue(IsRecentColorsVisibleProperty); } - set { this.SetValue(IsRecentColorsVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsRecentColorsVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsRecentColorsVisibleProperty = - DependencyProperty.Register("IsRecentColorsVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); - - - - #endregion - - #region Columns - - /// - /// Gets or sets number of color gallery columns. It works only when Mode is ThemeColors - /// - public int Columns - { - get { return (int)this.GetValue(ColumnsProperty); } - set { this.SetValue(ColumnsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Columns. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ColumnsProperty = - DependencyProperty.Register("Columns", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(10, OnColumnsChanged, CoerceColumns)); - - private static object CoerceColumns(DependencyObject d, object basevalue) - { - int value = (int)basevalue; - if (value < 1) return 1; - return basevalue; - } - - private static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as ColorGallery).UpdateGradients(); - } - - #endregion - - #region StandardColorGridRows - - /// - /// Gets or set number of standard color rows. Work only when Mode is ThemeColors - /// - public int StandardColorGridRows - { - get { return (int)this.GetValue(StandardColorGridRowsProperty); } - set { this.SetValue(StandardColorGridRowsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for StandardColorGridRows. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty StandardColorGridRowsProperty = - DependencyProperty.Register("StandardColorGridRows", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(0, OnStandardColorGridRowsChanged, CoeceGridRows)); - - private static object CoeceGridRows(DependencyObject d, object basevalue) - { - int value = (int)basevalue; - if (value < 0) return 0; - return basevalue; - } - - private static void OnStandardColorGridRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as ColorGallery).UpdateGradients(); - } - - #endregion - - #region ThemeColorGridRows - - /// - /// Gets or set number of theme color rows. Work only when Mode is ThemeColors - /// - public int ThemeColorGridRows - { - get { return (int)this.GetValue(ThemeColorGridRowsProperty); } - set { this.SetValue(ThemeColorGridRowsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ThemeColorGridRows. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ThemeColorGridRowsProperty = - DependencyProperty.Register("ThemeColorGridRows", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(0, OnThemeColorGridRowsChanged, CoeceGridRows)); - - private static void OnThemeColorGridRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as ColorGallery).UpdateGradients(); - } - - #endregion - - #region SelectedColor - - /// - /// Gets or sets selected color - /// - public Color? SelectedColor - { - get { return (Color?)this.GetValue(SelectedColorProperty); } - set { this.SetValue(SelectedColorProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectedColor. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedColorProperty = - DependencyProperty.Register("SelectedColor", typeof(Color?), typeof(ColorGallery), new UIPropertyMetadata(null, OnSelectedColorChanged)); - - // Handles selected color changed - private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gallery = d as ColorGallery; - - if (gallery == null) - { - return; - } - - // Raise event - gallery.RaiseEvent(new RoutedEventArgs(SelectedColorChangedEvent)); - - // Set color in gallery - var color = (Color?)e.NewValue; - gallery.UpdateSelectedColor(color); - } - - private void UpdateSelectedColor(Color? color) - { - if (this.isSelectionChanging - || this.isTemplateApplied == false) - { - return; - } - - this.isSelectionChanging = true; - var isSetted = false; - - // Check menu items - if (color.HasValue == false) - { - isSetted = true; - this.automaticButton.IsChecked = true; - this.noColorButton.IsChecked = false; - } - else if (color.Value == Colors.Transparent) - { - isSetted = true; - this.automaticButton.IsChecked = false; - this.noColorButton.IsChecked = true; - } - else - { - this.automaticButton.IsChecked = false; - this.noColorButton.IsChecked = false; - } - - // Remove selection from others - for (var i = 0; i < this.listBoxes.Count; i++) - { - if (isSetted == false - && this.listBoxes[i].Visibility == Visibility.Visible) - { - if (this.listBoxes[i].Items.Contains(color.Value)) - { - this.listBoxes[i].SelectedItem = color.Value; - isSetted = true; - } - } - else - { - this.listBoxes[i].SelectedItem = null; - } - } - - this.isSelectionChanging = false; - } - - #endregion - - #region ThemeColors - - private ObservableCollection themeColors; - - /// - /// Gets collection of theme colors - /// - public ObservableCollection ThemeColors - { - get - { - if (this.themeColors == null) - { - this.themeColors = new ObservableCollection(); - this.themeColors.CollectionChanged += this.OnThemeColorsChanged; - } - return this.themeColors; - } - } - - private void OnThemeColorsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.UpdateGradients(); - } - - /// - /// Gets or sets theme colors source - /// - public IEnumerable ThemeColorsSource - { - get { return (IEnumerable)this.GetValue(ThemeColorsSourceProperty); } - set { this.SetValue(ThemeColorsSourceProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ThemeColorsSource. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ThemeColorsSourceProperty = - DependencyProperty.Register("ThemeColorsSource", typeof(IEnumerable), typeof(ColorGallery), new UIPropertyMetadata(null, OnThemeColorsSourceChanged)); - - private static void OnThemeColorsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ColorGallery gal = d as ColorGallery; - gal.ThemeColors.Clear(); - if (e.NewValue != null) - { - foreach (Color color in (e.NewValue as IEnumerable)) - { - gal.ThemeColors.Add(color); - } - } - } - - #endregion - - #region ThemeGradients - - /// - /// Gets theme gradients collection - /// - public Color[] ThemeGradients - { - get { return (Color[])this.GetValue(ThemeGradientsProperty); } - private set { this.SetValue(ThemeGradientsPropertyKey, value); } - } - - // - private static readonly DependencyPropertyKey ThemeGradientsPropertyKey = - DependencyProperty.RegisterReadOnly("ThemeGradients", typeof(Color[]), typeof(ColorGallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for ThemeGradients. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ThemeGradientsProperty = ThemeGradientsPropertyKey.DependencyProperty; - - #endregion - - #region StandardGradients - - /// - /// Gets standart gradients collection - /// - public Color[] StandardGradients - { - get { return (Color[])this.GetValue(StandardGradientsProperty); } - private set { this.SetValue(StandardGradientsPropertyKey, value); } - } - - - private static readonly DependencyPropertyKey StandardGradientsPropertyKey = - DependencyProperty.RegisterReadOnly("StandardGradients", typeof(Color[]), typeof(ColorGallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for ThemeGradients. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty StandardGradientsProperty = StandardGradientsPropertyKey.DependencyProperty; - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when selection color is changed - /// - public event RoutedEventHandler SelectedColorChanged - { - add - { - this.AddHandler(SelectedColorChangedEvent, value); - } - remove - { - this.RemoveHandler(SelectedColorChangedEvent, value); - } - } - /// - /// Identifies the SelectedColorChanged routed event. - /// - public static readonly RoutedEvent SelectedColorChangedEvent = EventManager.RegisterRoutedEvent("SelectedColorChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorGallery)); - - /// - /// Raises SelectedColorChanged event - /// - public void RaiseSelectedColorChanged() - { - this.RaiseEvent(new RoutedEventArgs(SelectedColorChangedEvent, this)); - } - - /// - /// Occurs whether more colors menu item is clicked - /// - public event EventHandler MoreColorsExecuting; - - #endregion - - #region Initializing - - /// - /// Static constructor - /// - static ColorGallery() - { - Type type = typeof(ColorGallery); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - ContextMenuService.Attach(type); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(ColorGallery)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public ColorGallery() - { - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (this.moreColorsButton != null) - this.moreColorsButton.Click += this.OnMoreColorsClick; - this.moreColorsButton = this.GetTemplateChild("PART_MoreColors") as MenuItem; - if (this.moreColorsButton != null) - this.moreColorsButton.Click += this.OnMoreColorsClick; - - if (this.noColorButton != null) - this.noColorButton.Click -= this.OnNoColorClick; - this.noColorButton = this.GetTemplateChild("PART_NoColor") as MenuItem; - if (this.noColorButton != null) - this.noColorButton.Click += this.OnNoColorClick; - - if (this.automaticButton != null) - this.automaticButton.Click -= this.OnAutomaticClick; - this.automaticButton = this.GetTemplateChild("PART_AutomaticColor") as MenuItem; - if (this.automaticButton != null) - this.automaticButton.Click += this.OnAutomaticClick; - - // List boxes - this.listBoxes.Clear(); - - if (this.themeColorsListBox != null) - this.themeColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; - this.themeColorsListBox = this.GetTemplateChild("PART_ThemeColorsListBox") as ListBox; - this.listBoxes.Add(this.themeColorsListBox); - if (this.themeColorsListBox != null) - this.themeColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; - - if (this.themeGradientsListBox != null) - this.themeGradientsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; - this.themeGradientsListBox = this.GetTemplateChild("PART_ThemeGradientColorsListBox") as ListBox; - this.listBoxes.Add(this.themeGradientsListBox); - if (this.themeGradientsListBox != null) - this.themeGradientsListBox.SelectionChanged += this.OnListBoxSelectedChanged; - - if (this.standardColorsListBox != null) - this.standardColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; - this.standardColorsListBox = this.GetTemplateChild("PART_StandardColorsListBox") as ListBox; - this.listBoxes.Add(this.standardColorsListBox); - if (this.standardColorsListBox != null) - this.standardColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; - - if (this.standardGradientsListBox != null) - this.standardGradientsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; - this.standardGradientsListBox = this.GetTemplateChild("PART_StandardGradientColorsListBox") as ListBox; - this.listBoxes.Add(this.standardGradientsListBox); - if (this.standardGradientsListBox != null) - this.standardGradientsListBox.SelectionChanged += this.OnListBoxSelectedChanged; - - if (this.recentColorsListBox != null) - this.recentColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; - this.recentColorsListBox = this.GetTemplateChild("PART_RecentColorsListBox") as ListBox; - this.listBoxes.Add(this.recentColorsListBox); - if (this.recentColorsListBox != null) - this.recentColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; - - this.isTemplateApplied = true; - - this.UpdateSelectedColor(this.SelectedColor); - } - - #endregion - - #region Private Methods - - private static IntPtr customColors = IntPtr.Zero; - private readonly int[] colorsArray = new int[16]; - - private void OnMoreColorsClick(object sender, RoutedEventArgs e) - { - if (this.MoreColorsExecuting != null) - { - MoreColorsExecutingEventArgs args = new MoreColorsExecutingEventArgs(); - this.MoreColorsExecuting(this, args); - if (!args.Canceled) - { - Color color = args.Color; - if (RecentColors.Contains(color)) RecentColors.Remove(color); - RecentColors.Insert(0, color); - this.recentColorsListBox.SelectedIndex = 0; - } - } - else - { - NativeMethods.CHOOSECOLOR chooseColor = new NativeMethods.CHOOSECOLOR(); - Window wnd = Window.GetWindow(this); - if (wnd != null) chooseColor.hwndOwner = new WindowInteropHelper(wnd).Handle; - chooseColor.Flags = NativeMethods.CC_ANYCOLOR; - if (customColors == IntPtr.Zero) - { - // Set custom colors) - for (int i = 0; i < this.colorsArray.Length; i++) - this.colorsArray[i] = 0x00FFFFFF; - customColors = GCHandle.Alloc(this.colorsArray, GCHandleType.Pinned).AddrOfPinnedObject(); - } - chooseColor.lpCustColors = customColors; - if (NativeMethods.ChooseColor(chooseColor)) - { - Color color = ConvertFromWin32Color(chooseColor.rgbResult); - if (RecentColors.Contains(color)) RecentColors.Remove(color); - RecentColors.Insert(0, color); - this.recentColorsListBox.SelectedIndex = 0; - } - } - } - - private static Color ConvertFromWin32Color(int color) - { - int r = color & 0x000000FF; - int g = (color & 0x0000FF00) >> 8; - int b = (color & 0x00FF0000) >> 16; - return Color.FromArgb(255, (byte)r, (byte)g, (byte)b); - } - - private void OnAutomaticClick(object sender, RoutedEventArgs e) - { - this.isSelectionChanging = true; - this.noColorButton.IsChecked = false; - this.automaticButton.IsChecked = true; - // Remove selection from listboxes - for (int i = 0; i < this.listBoxes.Count; i++) - { - this.listBoxes[i].SelectedItem = null; - } - - this.SelectedColor = null; - this.isSelectionChanging = false; - } - - private void OnNoColorClick(object sender, RoutedEventArgs e) - { - this.isSelectionChanging = true; - this.noColorButton.IsChecked = true; - this.automaticButton.IsChecked = false; - // Remove selection from listboxes - for (int i = 0; i < this.listBoxes.Count; i++) - { - this.listBoxes[i].SelectedItem = null; - } - - this.SelectedColor = Colors.Transparent; - this.isSelectionChanging = false; - } - - private void OnListBoxSelectedChanged(object sender, SelectionChangedEventArgs e) - { - if (this.isSelectionChanging) return; - this.isSelectionChanging = true; - if (e.AddedItems != null && e.AddedItems.Count > 0) - { - // Remove selection from others - this.noColorButton.IsChecked = false; - this.automaticButton.IsChecked = false; - for (int i = 0; i < this.listBoxes.Count; i++) - { - if (this.listBoxes[i] != sender) - this.listBoxes[i].SelectedItem = null; - } - this.SelectedColor = (Color)e.AddedItems[0]; - PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); - } - this.isSelectionChanging = false; - } - - private void UpdateGradients() - { - if ((this.Mode == ColorGalleryMode.ThemeColors) && (this.Columns > 0)) - { - if (this.ThemeColorGridRows > 0) - { - this.ThemeGradients = this.GenerateThemeGradients(); - } - else - this.ThemeGradients = null; - - if (this.StandardColorGridRows > 0) - { - this.StandardGradients = this.GenerateStandardGradients(); - } - else - this.StandardGradients = null; - } - else - { - this.StandardGradients = null; - this.ThemeGradients = null; - } - } - - private Color[] GenerateStandardGradients() - { - int count = Math.Min(this.Columns, StandardThemeColors.Length); - Color[] result = new Color[this.Columns *this.StandardColorGridRows]; - for (int i = 0; i < count; i++) - { - Color[] colors = GetGradient(StandardThemeColors[i], this.StandardColorGridRows); - for (int j = 0; j < this.StandardColorGridRows; j++) - { - result[i + j *this.Columns] = colors[j]; - } - } - return result; - } - - private Color[] GenerateThemeGradients() - { - int count = Math.Min(this.Columns, this.ThemeColors.Count); - Color[] result = new Color[this.Columns *this.ThemeColorGridRows]; - for (int i = 0; i < count; i++) - { - Color[] colors = GetGradient(this.ThemeColors[i], this.ThemeColorGridRows); - for (int j = 0; j < this.ThemeColorGridRows; j++) - { - result[i + j *this.Columns] = colors[j]; - } - } - return result; - } - - #endregion - - #region Gradient Generation - - /// - /// Returns brightness of the given color from 0..1 - /// - /// Color - /// Brightness of the given color from 0..1 - static double GetBrightness(Color color) - { - double summ = ((double)color.R) + ((double)color.G) + ((double)color.B); - return summ / (255.0 * 3.0); - } - - // Makes the given color lighter - static Color Lighter(Color color, double power) - { - double totalAvailability = 255.0 * 3.0 - (double)color.R + (double)color.G + (double)color.B; - double redAvailability; - double greenAvailability; - double blueAvailability; - double needToBeAdded; - - if (color.R + color.G + color.B == 0) - { - redAvailability = 1.0 / 3.0; - greenAvailability = 1.0 / 3.0; - blueAvailability = 1.0 / 3.0; - needToBeAdded = power * 255.0 * 3.0; - } - else - { - redAvailability = (255.0 - (double)color.R) / totalAvailability; - greenAvailability = (255.0 - (double)color.G) / totalAvailability; - blueAvailability = (255.0 - (double)color.B) / totalAvailability; - needToBeAdded = ((double)color.R + (double)color.G + (double)color.B) * (power - 1); - } - - - Color result = Color.FromRgb( - (byte)(color.R + ((byte)(redAvailability * needToBeAdded))), - (byte)(color.G + ((byte)(greenAvailability * needToBeAdded))), - (byte)(color.B + ((byte)(blueAvailability * needToBeAdded)))); - - return result; - } - - // Makes the given color darker - static Color Darker(Color color, double power) - { - double totalAvailability = (double)color.R + (double)color.G + (double)color.B; - double redAvailability = ((double)color.R) / totalAvailability; - double greenAvailability = ((double)color.G) / totalAvailability; - double blueAvailability = ((double)color.B) / totalAvailability; - - double needToBeAdded = ((double)color.R + (double)color.G + (double)color.B); - needToBeAdded = needToBeAdded - needToBeAdded * power; - - Color result = Color.FromRgb( - (byte)(color.R - ((byte)(redAvailability * needToBeAdded))), - (byte)(color.G - ((byte)(greenAvailability * needToBeAdded))), - (byte)(color.B - ((byte)(blueAvailability * needToBeAdded)))); - - return result; - } - - // Makes a new color from the given with new brightness - static Color Rebright(Color color, double newBrightness) - { - double currentBrightness = GetBrightness(color); - double power = currentBrightness != 0.0 ? newBrightness / currentBrightness : (1.0 + newBrightness); - - // TODO: round power to make nice numbers - // ... - - if (power > 1.0) return Lighter(color, power); - else return Darker(color, power); - } - - /// - /// Makes gradient colors from lighter to darker - /// - /// Base color - /// Count of items in the gradient - /// Colors from lighter to darker - static Color[] GetGradient(Color color, int count) - { - const double lowBrightness = 0.15; - const double highBrightness = 0.85; - Color[] result = new Color[count]; - - for (int i = 0; i < count; i++) - { - double brightness = lowBrightness + ((double)i) * (highBrightness - lowBrightness) / (double)count; - result[count - i - 1] = Rebright(color, brightness); - } - - return result; - } - - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.Diagnostics; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Interop; + using System.Windows.Markup; + using System.Windows.Media; + using System.Windows.Threading; + + /// + /// Represents color gallery modes + /// + public enum ColorGalleryMode + { + /// + /// Color gallery displays only fixed highlight colors + /// + HighlightColors = 0, + + /// + /// Color gallery displays only fixed standart colors + /// + StandardColors, + + /// + /// Color gallery displays theme colors + /// + ThemeColors + } + + /// + /// Date template selector for gradients + /// + public class ColorGradientItemTemplateSelector : DataTemplateSelector + { + /// + /// When overridden in a derived class, returns a based on custom logic. + /// + /// + /// Returns a or null. The default value is null. + /// + /// The data object for which to select the template.The data-bound object. + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + if (item == null) + { + return null; + } + + ListBox listBox = null; + var parent = container; + while (parent != null) + { + parent = VisualTreeHelper.GetParent(parent); + listBox = parent as ListBox; + if (listBox != null) + { + break; + } + } + + if (listBox == null) + { + return null; + } + + ColorGallery colorGallery = null; + while (parent != null) + { + parent = VisualTreeHelper.GetParent(parent); + colorGallery = parent as ColorGallery; + if (colorGallery != null) break; + } + + if (colorGallery == null) + { + return null; + } + + var index = listBox.Items.IndexOf(item); + if (index < colorGallery.Columns) + { + return listBox.TryFindResource("GradientColorTopDataTemplate") as DataTemplate; + } + + if (index >= listBox.Items.Count - colorGallery.Columns) + { + return listBox.TryFindResource("GradientColorBottomDataTemplate") as DataTemplate; + } + + return listBox.TryFindResource("GradientColorCenterDataTemplate") as DataTemplate; + } + + } + + /// + /// More colors event args + /// + public class MoreColorsExecutingEventArgs : EventArgs + { + /// + /// Gets or sets choosed color + /// + public Color Color { get; set; } + /// + /// Gets or sets a value indicating whether more colors is canceled + /// + public bool Canceled { get; set; } + } + + /// + /// Represents color gallery + /// + [ContentProperty("ThemeColors")] + public class ColorGallery : Control + { + #region Constants + + /// + /// Hightlight colors array + /// + public static readonly Color[] HighlightColors = new Color[] + { + Color.FromRgb(0xFF ,0xFF ,0x00), + Color.FromRgb(0x00 ,0xFF ,0x00), + Color.FromRgb(0x00 ,0xFF ,0xFF), + + Color.FromRgb(0xFF ,0x00 ,0xFF), + Color.FromRgb(0x00 ,0x00 ,0xFF), + Color.FromRgb(0xFF ,0x00 ,0x00), + + Color.FromRgb(0x00 ,0x00 ,0x80), + Color.FromRgb(0x00 ,0x80 ,0x80), + Color.FromRgb(0x00 ,0x80 ,0x00), + + Color.FromRgb(0x80 ,0x00 ,0x80), + Color.FromRgb(0x80 ,0x00 ,0x00), + Color.FromRgb(0x80 ,0x80 ,0x00), + + Color.FromRgb(0x80 ,0x80 ,0x80), + Color.FromRgb(0xC0 ,0xC0 ,0xC0), + Color.FromRgb(0x00 ,0x00 ,0x00), + }; + + /// + /// Standard colors array + /// + public static readonly Color[] StandardColors = new Color[] + { + Color.FromRgb(0xFF ,0xFF ,0xFF), + Color.FromRgb(0xFF ,0x00 ,0x00), + Color.FromRgb(0xC0 ,0x50 ,0x4D), + Color.FromRgb(0xD1 ,0x63 ,0x49), + Color.FromRgb(0xDD ,0x84 ,0x84), + + Color.FromRgb(0xCC ,0xCC ,0xCC), + Color.FromRgb(0xFF ,0xC0 ,0x00), + Color.FromRgb(0xF7 ,0x96 ,0x46), + Color.FromRgb(0xD1 ,0x90 ,0x49), + Color.FromRgb(0xF3 ,0xA4 ,0x47), + + Color.FromRgb(0xA5 ,0xA5 ,0xA5), + Color.FromRgb(0xFF ,0xFF ,0x00), + Color.FromRgb(0x9B ,0xBB ,0x59), + Color.FromRgb(0xCC ,0xB4 ,0x00), + Color.FromRgb(0xDF ,0xCE ,0x04), + + Color.FromRgb(0x66 ,0x66 ,0x66), + Color.FromRgb(0x00 ,0xB0 ,0x50), + Color.FromRgb(0x4B ,0xAC ,0xC6), + Color.FromRgb(0x8F ,0xB0 ,0x8C), + Color.FromRgb(0xA5 ,0xB5 ,0x92), + + Color.FromRgb(0x33 ,0x33 ,0x33), + Color.FromRgb(0x00 ,0x4D ,0xBB), + Color.FromRgb(0x4F ,0x81 ,0xBD), + Color.FromRgb(0x64 ,0x6B ,0x86), + Color.FromRgb(0x80 ,0x9E ,0xC2), + + Color.FromRgb(0x00 ,0x00 ,0x00), + Color.FromRgb(0x9B ,0x00 ,0xD3), + Color.FromRgb(0x80 ,0x64 ,0xA2), + Color.FromRgb(0x9E ,0x7C ,0x7C), + Color.FromRgb(0x9C ,0x85 ,0xC0), + }; + + /// + /// Standard colors array in ThemeColor mode + /// + public static readonly Color[] StandardThemeColors = new Color[] + { + Color.FromRgb(0xC0 ,0x00 ,0x00), + Color.FromRgb(0xFF ,0x00 ,0x00), + Color.FromRgb(0xFF ,0xC0 ,0x00), + Color.FromRgb(0xFF ,0xFF ,0x00), + Color.FromRgb(0x92 ,0xD0 ,0x50), + Color.FromRgb(0x00 ,0xB0 ,0x50), + Color.FromRgb(0x00 ,0xB0 ,0xF0), + Color.FromRgb(0x00 ,0x70 ,0xC0), + Color.FromRgb(0x00 ,0x20 ,0x60), + Color.FromRgb(0x70 ,0x30 ,0xA0), + }; + + #endregion + + #region RecentItems + + private static ObservableCollection recentColors; + + /// + /// Gets recent colors collection + /// + public static ObservableCollection RecentColors + { + get + { + if (recentColors == null) recentColors = new ObservableCollection(); + return recentColors; + } + } + + #endregion + + #region Fields + + private MenuItem noColorButton; + private MenuItem automaticButton; + + private MenuItem moreColorsButton; + + private ListBox themeColorsListBox; + private ListBox themeGradientsListBox; + private ListBox standardColorsListBox; + private ListBox standardGradientsListBox; + private ListBox recentColorsListBox; + + private readonly List listBoxes = new List(); + + private bool isSelectionChanging; + + private bool isTemplateApplied; + + + #endregion + + #region Properties + + #region Mode + + /// + /// Gets or sets color gallery mode + /// + public ColorGalleryMode Mode + { + get { return (ColorGalleryMode)this.GetValue(ModeProperty); } + set { this.SetValue(ModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Mode. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ModeProperty = + DependencyProperty.Register("Mode", typeof(ColorGalleryMode), typeof(ColorGallery), new UIPropertyMetadata(ColorGalleryMode.StandardColors, OnModeChanged)); + + private static void OnModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as ColorGallery).UpdateGradients(); + } + + #endregion + + #region Chip Size + + /// + /// Gets or sets chip width + /// + public double ChipWidth + { + get { return (double)this.GetValue(ChipWidthProperty); } + set { this.SetValue(ChipWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ChipWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ChipWidthProperty = + DependencyProperty.Register("ChipWidth", typeof(double), typeof(ColorGallery), new UIPropertyMetadata(13.0, null, CoerceChipSize)); + + private static object CoerceChipSize(DependencyObject d, object basevalue) + { + double value = (double)basevalue; + if (value < 0) return 0; + return basevalue; + } + + /// + /// Gets or sets chip height + /// + public double ChipHeight + { + get { return (double)this.GetValue(ChipHeightProperty); } + set { this.SetValue(ChipHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ChipHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ChipHeightProperty = + DependencyProperty.Register("ChipHeight", typeof(double), typeof(ColorGallery), new UIPropertyMetadata(13.0, null, CoerceChipSize)); + + #endregion + + #region IsAutomaticColorButtonVisible + + /// + /// Gets or sets a value indicating whether Automatic button is visible + /// + public bool IsAutomaticColorButtonVisible + { + get { return (bool)this.GetValue(IsAutomaticColorButtonVisibleProperty); } + set { this.SetValue(IsAutomaticColorButtonVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsAutomaticColorButtonVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsAutomaticColorButtonVisibleProperty = + DependencyProperty.Register("IsAutomaticColorButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); + + #endregion + + #region IsNoColorButtonVisible + + /// + /// Gets or sets a value indicating whether No color button is visible + /// + public bool IsNoColorButtonVisible + { + get { return (bool)this.GetValue(IsNoColorButtonVisibleProperty); } + set { this.SetValue(IsNoColorButtonVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsNoColorButtonVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsNoColorButtonVisibleProperty = + DependencyProperty.Register("IsNoColorButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); + + #endregion + + #region IsMoreColorsButtonVisible + + /// + /// Gets or sets a value indicating whether More Colors button is visible + /// + public bool IsMoreColorsButtonVisible + { + get { return (bool)this.GetValue(IsMoreColorsButtonVisibleProperty); } + set { this.SetValue(IsMoreColorsButtonVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsMoreColorsButtonVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsMoreColorsButtonVisibleProperty = + DependencyProperty.Register("IsMoreColorsButtonVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); + + #endregion + + #region IsRecentColorsVisible + + /// + /// Gets or set a value indicating whether recent colors group displayed. Work only when Mode is ThemeColors + /// + public bool IsRecentColorsVisible + { + get { return (bool)this.GetValue(IsRecentColorsVisibleProperty); } + set { this.SetValue(IsRecentColorsVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsRecentColorsVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsRecentColorsVisibleProperty = + DependencyProperty.Register("IsRecentColorsVisible", typeof(bool), typeof(ColorGallery), new UIPropertyMetadata(true)); + + + + #endregion + + #region Columns + + /// + /// Gets or sets number of color gallery columns. It works only when Mode is ThemeColors + /// + public int Columns + { + get { return (int)this.GetValue(ColumnsProperty); } + set { this.SetValue(ColumnsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Columns. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ColumnsProperty = + DependencyProperty.Register("Columns", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(10, OnColumnsChanged, CoerceColumns)); + + private static object CoerceColumns(DependencyObject d, object basevalue) + { + int value = (int)basevalue; + if (value < 1) return 1; + return basevalue; + } + + private static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as ColorGallery).UpdateGradients(); + } + + #endregion + + #region StandardColorGridRows + + /// + /// Gets or set number of standard color rows. Work only when Mode is ThemeColors + /// + public int StandardColorGridRows + { + get { return (int)this.GetValue(StandardColorGridRowsProperty); } + set { this.SetValue(StandardColorGridRowsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for StandardColorGridRows. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty StandardColorGridRowsProperty = + DependencyProperty.Register("StandardColorGridRows", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(0, OnStandardColorGridRowsChanged, CoeceGridRows)); + + private static object CoeceGridRows(DependencyObject d, object basevalue) + { + int value = (int)basevalue; + if (value < 0) return 0; + return basevalue; + } + + private static void OnStandardColorGridRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as ColorGallery).UpdateGradients(); + } + + #endregion + + #region ThemeColorGridRows + + /// + /// Gets or set number of theme color rows. Work only when Mode is ThemeColors + /// + public int ThemeColorGridRows + { + get { return (int)this.GetValue(ThemeColorGridRowsProperty); } + set { this.SetValue(ThemeColorGridRowsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ThemeColorGridRows. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ThemeColorGridRowsProperty = + DependencyProperty.Register("ThemeColorGridRows", typeof(int), typeof(ColorGallery), new UIPropertyMetadata(0, OnThemeColorGridRowsChanged, CoeceGridRows)); + + private static void OnThemeColorGridRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + (d as ColorGallery).UpdateGradients(); + } + + #endregion + + #region SelectedColor + + /// + /// Gets or sets selected color + /// + public Color? SelectedColor + { + get { return (Color?)this.GetValue(SelectedColorProperty); } + set { this.SetValue(SelectedColorProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectedColor. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedColorProperty = + DependencyProperty.Register("SelectedColor", typeof(Color?), typeof(ColorGallery), new UIPropertyMetadata(null, OnSelectedColorChanged)); + + // Handles selected color changed + private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var gallery = d as ColorGallery; + + if (gallery == null) + { + return; + } + + // Raise event + gallery.RaiseEvent(new RoutedEventArgs(SelectedColorChangedEvent)); + + // Set color in gallery + var color = (Color?)e.NewValue; + gallery.UpdateSelectedColor(color); + } + + private void UpdateSelectedColor(Color? color) + { + if (this.isSelectionChanging + || this.isTemplateApplied == false) + { + return; + } + + this.isSelectionChanging = true; + var isSetted = false; + + // Check menu items + if (color.HasValue == false) + { + isSetted = true; + this.automaticButton.IsChecked = true; + this.noColorButton.IsChecked = false; + } + else if (color.Value == Colors.Transparent) + { + isSetted = true; + this.automaticButton.IsChecked = false; + this.noColorButton.IsChecked = true; + } + else + { + this.automaticButton.IsChecked = false; + this.noColorButton.IsChecked = false; + } + + // Remove selection from others + for (var i = 0; i < this.listBoxes.Count; i++) + { + if (isSetted == false + && this.listBoxes[i].Visibility == Visibility.Visible) + { + if (this.listBoxes[i].Items.Contains(color.Value)) + { + this.listBoxes[i].SelectedItem = color.Value; + isSetted = true; + } + } + else + { + this.listBoxes[i].SelectedItem = null; + } + } + + this.isSelectionChanging = false; + } + + #endregion + + #region ThemeColors + + private ObservableCollection themeColors; + + /// + /// Gets collection of theme colors + /// + public ObservableCollection ThemeColors + { + get + { + if (this.themeColors == null) + { + this.themeColors = new ObservableCollection(); + this.themeColors.CollectionChanged += this.OnThemeColorsChanged; + } + return this.themeColors; + } + } + + private void OnThemeColorsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.UpdateGradients(); + } + + /// + /// Gets or sets theme colors source + /// + public IEnumerable ThemeColorsSource + { + get { return (IEnumerable)this.GetValue(ThemeColorsSourceProperty); } + set { this.SetValue(ThemeColorsSourceProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ThemeColorsSource. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ThemeColorsSourceProperty = + DependencyProperty.Register("ThemeColorsSource", typeof(IEnumerable), typeof(ColorGallery), new UIPropertyMetadata(null, OnThemeColorsSourceChanged)); + + private static void OnThemeColorsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ColorGallery gal = d as ColorGallery; + gal.ThemeColors.Clear(); + if (e.NewValue != null) + { + foreach (Color color in (e.NewValue as IEnumerable)) + { + gal.ThemeColors.Add(color); + } + } + } + + #endregion + + #region ThemeGradients + + /// + /// Gets theme gradients collection + /// + public Color[] ThemeGradients + { + get { return (Color[])this.GetValue(ThemeGradientsProperty); } + private set { this.SetValue(ThemeGradientsPropertyKey, value); } + } + + // + private static readonly DependencyPropertyKey ThemeGradientsPropertyKey = + DependencyProperty.RegisterReadOnly("ThemeGradients", typeof(Color[]), typeof(ColorGallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for ThemeGradients. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ThemeGradientsProperty = ThemeGradientsPropertyKey.DependencyProperty; + + #endregion + + #region StandardGradients + + /// + /// Gets standart gradients collection + /// + public Color[] StandardGradients + { + get { return (Color[])this.GetValue(StandardGradientsProperty); } + private set { this.SetValue(StandardGradientsPropertyKey, value); } + } + + + private static readonly DependencyPropertyKey StandardGradientsPropertyKey = + DependencyProperty.RegisterReadOnly("StandardGradients", typeof(Color[]), typeof(ColorGallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for ThemeGradients. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty StandardGradientsProperty = StandardGradientsPropertyKey.DependencyProperty; + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when selection color is changed + /// + public event RoutedEventHandler SelectedColorChanged + { + add + { + this.AddHandler(SelectedColorChangedEvent, value); + } + remove + { + this.RemoveHandler(SelectedColorChangedEvent, value); + } + } + /// + /// Identifies the SelectedColorChanged routed event. + /// + public static readonly RoutedEvent SelectedColorChangedEvent = EventManager.RegisterRoutedEvent("SelectedColorChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ColorGallery)); + + /// + /// Raises SelectedColorChanged event + /// + public void RaiseSelectedColorChanged() + { + this.RaiseEvent(new RoutedEventArgs(SelectedColorChangedEvent, this)); + } + + /// + /// Occurs whether more colors menu item is clicked + /// + public event EventHandler MoreColorsExecuting; + + #endregion + + #region Initializing + + /// + /// Static constructor + /// + static ColorGallery() + { + Type type = typeof(ColorGallery); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + ContextMenuService.Attach(type); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(ColorGallery)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public ColorGallery() + { + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (this.moreColorsButton != null) + this.moreColorsButton.Click += this.OnMoreColorsClick; + this.moreColorsButton = this.GetTemplateChild("PART_MoreColors") as MenuItem; + if (this.moreColorsButton != null) + this.moreColorsButton.Click += this.OnMoreColorsClick; + + if (this.noColorButton != null) + this.noColorButton.Click -= this.OnNoColorClick; + this.noColorButton = this.GetTemplateChild("PART_NoColor") as MenuItem; + if (this.noColorButton != null) + this.noColorButton.Click += this.OnNoColorClick; + + if (this.automaticButton != null) + this.automaticButton.Click -= this.OnAutomaticClick; + this.automaticButton = this.GetTemplateChild("PART_AutomaticColor") as MenuItem; + if (this.automaticButton != null) + this.automaticButton.Click += this.OnAutomaticClick; + + // List boxes + this.listBoxes.Clear(); + + if (this.themeColorsListBox != null) + this.themeColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; + this.themeColorsListBox = this.GetTemplateChild("PART_ThemeColorsListBox") as ListBox; + this.listBoxes.Add(this.themeColorsListBox); + if (this.themeColorsListBox != null) + this.themeColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; + + if (this.themeGradientsListBox != null) + this.themeGradientsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; + this.themeGradientsListBox = this.GetTemplateChild("PART_ThemeGradientColorsListBox") as ListBox; + this.listBoxes.Add(this.themeGradientsListBox); + if (this.themeGradientsListBox != null) + this.themeGradientsListBox.SelectionChanged += this.OnListBoxSelectedChanged; + + if (this.standardColorsListBox != null) + this.standardColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; + this.standardColorsListBox = this.GetTemplateChild("PART_StandardColorsListBox") as ListBox; + this.listBoxes.Add(this.standardColorsListBox); + if (this.standardColorsListBox != null) + this.standardColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; + + if (this.standardGradientsListBox != null) + this.standardGradientsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; + this.standardGradientsListBox = this.GetTemplateChild("PART_StandardGradientColorsListBox") as ListBox; + this.listBoxes.Add(this.standardGradientsListBox); + if (this.standardGradientsListBox != null) + this.standardGradientsListBox.SelectionChanged += this.OnListBoxSelectedChanged; + + if (this.recentColorsListBox != null) + this.recentColorsListBox.SelectionChanged -= this.OnListBoxSelectedChanged; + this.recentColorsListBox = this.GetTemplateChild("PART_RecentColorsListBox") as ListBox; + this.listBoxes.Add(this.recentColorsListBox); + if (this.recentColorsListBox != null) + this.recentColorsListBox.SelectionChanged += this.OnListBoxSelectedChanged; + + this.isTemplateApplied = true; + + this.UpdateSelectedColor(this.SelectedColor); + } + + #endregion + + #region Private Methods + + private static IntPtr customColors = IntPtr.Zero; + private readonly int[] colorsArray = new int[16]; + + private void OnMoreColorsClick(object sender, RoutedEventArgs e) + { + if (this.MoreColorsExecuting != null) + { + MoreColorsExecutingEventArgs args = new MoreColorsExecutingEventArgs(); + this.MoreColorsExecuting(this, args); + if (!args.Canceled) + { + Color color = args.Color; + if (RecentColors.Contains(color)) RecentColors.Remove(color); + RecentColors.Insert(0, color); + this.recentColorsListBox.SelectedIndex = 0; + } + } + else + { + NativeMethods.CHOOSECOLOR chooseColor = new NativeMethods.CHOOSECOLOR(); + Window wnd = Window.GetWindow(this); + if (wnd != null) chooseColor.hwndOwner = new WindowInteropHelper(wnd).Handle; + chooseColor.Flags = NativeMethods.CC_ANYCOLOR; + if (customColors == IntPtr.Zero) + { + // Set custom colors) + for (int i = 0; i < this.colorsArray.Length; i++) + this.colorsArray[i] = 0x00FFFFFF; + customColors = GCHandle.Alloc(this.colorsArray, GCHandleType.Pinned).AddrOfPinnedObject(); + } + chooseColor.lpCustColors = customColors; + if (NativeMethods.ChooseColor(chooseColor)) + { + Color color = ConvertFromWin32Color(chooseColor.rgbResult); + if (RecentColors.Contains(color)) RecentColors.Remove(color); + RecentColors.Insert(0, color); + this.recentColorsListBox.SelectedIndex = 0; + } + } + } + + private static Color ConvertFromWin32Color(int color) + { + int r = color & 0x000000FF; + int g = (color & 0x0000FF00) >> 8; + int b = (color & 0x00FF0000) >> 16; + return Color.FromArgb(255, (byte)r, (byte)g, (byte)b); + } + + private void OnAutomaticClick(object sender, RoutedEventArgs e) + { + this.isSelectionChanging = true; + this.noColorButton.IsChecked = false; + this.automaticButton.IsChecked = true; + // Remove selection from listboxes + for (int i = 0; i < this.listBoxes.Count; i++) + { + this.listBoxes[i].SelectedItem = null; + } + + this.SelectedColor = null; + this.isSelectionChanging = false; + } + + private void OnNoColorClick(object sender, RoutedEventArgs e) + { + this.isSelectionChanging = true; + this.noColorButton.IsChecked = true; + this.automaticButton.IsChecked = false; + // Remove selection from listboxes + for (int i = 0; i < this.listBoxes.Count; i++) + { + this.listBoxes[i].SelectedItem = null; + } + + this.SelectedColor = Colors.Transparent; + this.isSelectionChanging = false; + } + + private void OnListBoxSelectedChanged(object sender, SelectionChangedEventArgs e) + { + if (this.isSelectionChanging) return; + this.isSelectionChanging = true; + if (e.AddedItems != null && e.AddedItems.Count > 0) + { + // Remove selection from others + this.noColorButton.IsChecked = false; + this.automaticButton.IsChecked = false; + for (int i = 0; i < this.listBoxes.Count; i++) + { + if (this.listBoxes[i] != sender) + this.listBoxes[i].SelectedItem = null; + } + this.SelectedColor = (Color)e.AddedItems[0]; + PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); + } + this.isSelectionChanging = false; + } + + private void UpdateGradients() + { + if ((this.Mode == ColorGalleryMode.ThemeColors) && (this.Columns > 0)) + { + if (this.ThemeColorGridRows > 0) + { + this.ThemeGradients = this.GenerateThemeGradients(); + } + else + this.ThemeGradients = null; + + if (this.StandardColorGridRows > 0) + { + this.StandardGradients = this.GenerateStandardGradients(); + } + else + this.StandardGradients = null; + } + else + { + this.StandardGradients = null; + this.ThemeGradients = null; + } + } + + private Color[] GenerateStandardGradients() + { + int count = Math.Min(this.Columns, StandardThemeColors.Length); + Color[] result = new Color[this.Columns *this.StandardColorGridRows]; + for (int i = 0; i < count; i++) + { + Color[] colors = GetGradient(StandardThemeColors[i], this.StandardColorGridRows); + for (int j = 0; j < this.StandardColorGridRows; j++) + { + result[i + j *this.Columns] = colors[j]; + } + } + return result; + } + + private Color[] GenerateThemeGradients() + { + int count = Math.Min(this.Columns, this.ThemeColors.Count); + Color[] result = new Color[this.Columns *this.ThemeColorGridRows]; + for (int i = 0; i < count; i++) + { + Color[] colors = GetGradient(this.ThemeColors[i], this.ThemeColorGridRows); + for (int j = 0; j < this.ThemeColorGridRows; j++) + { + result[i + j *this.Columns] = colors[j]; + } + } + return result; + } + + #endregion + + #region Gradient Generation + + /// + /// Returns brightness of the given color from 0..1 + /// + /// Color + /// Brightness of the given color from 0..1 + static double GetBrightness(Color color) + { + double summ = ((double)color.R) + ((double)color.G) + ((double)color.B); + return summ / (255.0 * 3.0); + } + + // Makes the given color lighter + static Color Lighter(Color color, double power) + { + double totalAvailability = 255.0 * 3.0 - (double)color.R + (double)color.G + (double)color.B; + double redAvailability; + double greenAvailability; + double blueAvailability; + double needToBeAdded; + + if (color.R + color.G + color.B == 0) + { + redAvailability = 1.0 / 3.0; + greenAvailability = 1.0 / 3.0; + blueAvailability = 1.0 / 3.0; + needToBeAdded = power * 255.0 * 3.0; + } + else + { + redAvailability = (255.0 - (double)color.R) / totalAvailability; + greenAvailability = (255.0 - (double)color.G) / totalAvailability; + blueAvailability = (255.0 - (double)color.B) / totalAvailability; + needToBeAdded = ((double)color.R + (double)color.G + (double)color.B) * (power - 1); + } + + + Color result = Color.FromRgb( + (byte)(color.R + ((byte)(redAvailability * needToBeAdded))), + (byte)(color.G + ((byte)(greenAvailability * needToBeAdded))), + (byte)(color.B + ((byte)(blueAvailability * needToBeAdded)))); + + return result; + } + + // Makes the given color darker + static Color Darker(Color color, double power) + { + double totalAvailability = (double)color.R + (double)color.G + (double)color.B; + double redAvailability = ((double)color.R) / totalAvailability; + double greenAvailability = ((double)color.G) / totalAvailability; + double blueAvailability = ((double)color.B) / totalAvailability; + + double needToBeAdded = ((double)color.R + (double)color.G + (double)color.B); + needToBeAdded = needToBeAdded - needToBeAdded * power; + + Color result = Color.FromRgb( + (byte)(color.R - ((byte)(redAvailability * needToBeAdded))), + (byte)(color.G - ((byte)(greenAvailability * needToBeAdded))), + (byte)(color.B - ((byte)(blueAvailability * needToBeAdded)))); + + return result; + } + + // Makes a new color from the given with new brightness + static Color Rebright(Color color, double newBrightness) + { + double currentBrightness = GetBrightness(color); + double power = currentBrightness != 0.0 ? newBrightness / currentBrightness : (1.0 + newBrightness); + + // TODO: round power to make nice numbers + // ... + + if (power > 1.0) return Lighter(color, power); + else return Darker(color, power); + } + + /// + /// Makes gradient colors from lighter to darker + /// + /// Base color + /// Count of items in the gradient + /// Colors from lighter to darker + static Color[] GetGradient(Color color, int count) + { + const double lowBrightness = 0.15; + const double highBrightness = 0.85; + Color[] result = new Color[count]; + + for (int i = 0; i < count; i++) + { + double brightness = lowBrightness + ((double)i) * (highBrightness - lowBrightness) / (double)count; + result[count - i - 1] = Rebright(color, brightness); + } + + return result; + } + + + #endregion + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Controls/ComboBox.cs b/Fluent.Ribbon/Controls/ComboBox.cs new file mode 100644 index 000000000..d25adfaa3 --- /dev/null +++ b/Fluent.Ribbon/Controls/ComboBox.cs @@ -0,0 +1,971 @@ +namespace Fluent +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Threading; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Media; + using System.Windows.Media.Imaging; + using System.Windows.Threading; + using Fluent.Internal; + + /// + /// Represents custom Fluent UI ComboBox + /// + [TemplatePart(Name = "PART_ResizeBothThumb", Type = typeof(Thumb))] + [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))] + public class ComboBox : System.Windows.Controls.ComboBox, IQuickAccessItemProvider, IRibbonControl, IDropDownControl + { + #region Fields + + // Thumb to resize in both directions + private Thumb resizeBothThumb; + // Thumb to resize vertical + private Thumb resizeVerticalThumb; + + private IInputElement focusedElement; + + private Panel menuPanel; + + private Border dropDownBorder; + private Border contentBorder; + + private ContentPresenter contentSite; + + // Freezed image (created during snapping) + private Image snappedImage; + + // Is visual currently snapped + private bool isSnapped; + + private GalleryPanel galleryPanel; + + private ScrollViewer scrollViewer; + + private bool canSizeY; + + #endregion + + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ComboBox)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ComboBox)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ComboBox)); + + #endregion + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup { get; private set; } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ComboBox)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = d as ComboBox; + var oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) element.RemoveLogicalChild(oldElement); + var newElement = e.NewValue as FrameworkElement; + if (newElement != null) element.AddLogicalChild(newElement); + } + + #endregion + + #region Menu + + /// + /// Gets or sets menu to show in combo box bottom + /// + public RibbonMenu Menu + { + get { return (RibbonMenu)this.GetValue(MenuProperty); } + set { this.SetValue(MenuProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MenuProperty = + DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(ComboBox), new UIPropertyMetadata(null)); + + #endregion + + #region InputWidth + + /// + /// Gets or sets width of the value input part of combobox + /// + public double InputWidth + { + get { return (double)this.GetValue(InputWidthProperty); } + set { this.SetValue(InputWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty InputWidthProperty = + DependencyProperty.Register("InputWidth", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ItemHeight + + /// + /// Gets or sets items height + /// + public double ItemHeight + { + get { return (double)this.GetValue(ItemHeightProperty); } + set { this.SetValue(ItemHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region GroupBy + + /// + /// Gets or sets name of property which + /// will use to group items in the ComboBox. + /// + public string GroupBy + { + get { return (string)this.GetValue(GroupByProperty); } + set { this.SetValue(GroupByProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupBy. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupByProperty = + DependencyProperty.Register("GroupBy", typeof(string), + typeof(ComboBox), new UIPropertyMetadata(null)); + + #endregion + + #region ResizeMode + + /// + /// Gets or sets context menu resize mode + /// + public ContextMenuResizeMode ResizeMode + { + get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } + set { this.SetValue(ResizeModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeModeProperty = + DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(ComboBox), new UIPropertyMetadata(ContextMenuResizeMode.None)); + + #endregion + + #region Snapping + + /// + /// Snaps / Unsnaps the Visual + /// (remove visuals and substitute with freezed image) + /// + private bool IsSnapped + { + get { return this.isSnapped; } + set + { + if (value == this.isSnapped) return; + if (this.snappedImage == null) return; + if ((value) && (((int)this.contentSite.ActualWidth > 0) && ((int)this.contentSite.ActualHeight > 0))) + { + // Render the freezed image + RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor); + var renderTargetBitmap = new RenderTargetBitmap((int)this.contentSite.ActualWidth + (int)this.contentSite.Margin.Left + (int)this.contentSite.Margin.Right, + (int)this.contentSite.ActualHeight + (int)this.contentSite.Margin.Top + (int)this.contentSite.Margin.Bottom, 96, 96, + PixelFormats.Pbgra32); + renderTargetBitmap.Render(this.contentSite); + this.snappedImage.Source = renderTargetBitmap; + this.snappedImage.FlowDirection = this.FlowDirection; + /*snappedImage.Width = contentSite.ActualWidth; + snappedImage.Height = contentSite.ActualHeight;*/ + this.snappedImage.Visibility = Visibility.Visible; + this.contentSite.Visibility = Visibility.Hidden; + this.isSnapped = value; + } + else + { + this.snappedImage.Visibility = Visibility.Collapsed; + this.contentSite.Visibility = Visibility.Visible; + this.isSnapped = value; + } + + this.InvalidateVisual(); + } + } + + #endregion + + #region DropDownHeight + + /// + /// Gets or sets initial dropdown height + /// + public double DropDownHeight + { + get { return (double)this.GetValue(DropDownHeightProperty); } + set { this.SetValue(DropDownHeightProperty, value); } + } + + /// + /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding, + /// etc... + /// + public static readonly DependencyProperty DropDownHeightProperty = + DependencyProperty.Register("InitialDropDownHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ShowPopupOnTop + + /// + /// Gets a value indicating whether popup is shown on top; + /// + public bool ShowPopupOnTop + { + get { return (bool)this.GetValue(ShowPopupOnTopProperty); } + private set { this.SetValue(ShowPopupOnTopPropertyKey, value); } + } + + // + private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(ComboBox), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding, + /// etc... + /// + public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty; + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static ComboBox() + { + var type = typeof(ComboBox); + ToolTipService.Attach(type); + PopupService.Attach(type); + ContextMenuService.Attach(type); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(OnSelectionItemChanged, CoerceSelectedItem)); + } + + private static void OnSelectionItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var combo = d as ComboBox; + if (!combo.isQuickAccessOpened && !combo.isQuickAccessFocused && (combo.quickAccessCombo != null)) combo.UpdateQuickAccessCombo(); + } + + private static object CoerceSelectedItem(DependencyObject d, object basevalue) + { + var combo = d as ComboBox; + if (combo.isQuickAccessOpened || combo.isQuickAccessFocused) return combo.selectedItem; + return basevalue; + } + + /// + /// Default Constructor + /// + public ComboBox() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region QuickAccess + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + var combo = new ComboBox(); + RibbonControl.BindQuickAccessItem(this, combo); + RibbonControl.Bind(this, combo, "GroupBy", GroupByProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ActualWidth", WidthProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "InputWidth", InputWidthProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ItemHeight", ItemHeightProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "IsEditable", IsEditableProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ResizeMode", ResizeModeProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "Text", TextProperty, BindingMode.TwoWay); + + RibbonControl.Bind(this, combo, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, combo, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); + combo.DropDownOpened += this.OnQuickAccessOpened; + if (this.IsEditable) combo.GotFocus += this.OnQuickAccessTextBoxGetFocus; + this.quickAccessCombo = combo; + this.UpdateQuickAccessCombo(); + return combo; + } + + private void OnQuickAccessTextBoxGetFocus(object sender, RoutedEventArgs e) + { + this.isQuickAccessFocused = true; + if (!this.isQuickAccessOpened) this.Freeze(); + this.quickAccessCombo.LostFocus += this.OnQuickAccessTextBoxLostFocus; + } + + private void OnQuickAccessTextBoxLostFocus(object sender, RoutedEventArgs e) + { + this.quickAccessCombo.LostFocus -= this.OnQuickAccessTextBoxLostFocus; + if (!this.isQuickAccessOpened) this.Unfreeze(); + this.isQuickAccessFocused = false; + } + + private bool isQuickAccessFocused; + private bool isQuickAccessOpened; + private object selectedItem; + private ComboBox quickAccessCombo; + + private void OnQuickAccessOpened(object sender, EventArgs e) + { + this.isQuickAccessOpened = true; + this.quickAccessCombo.DropDownClosed += this.OnQuickAccessMenuClosed; + this.quickAccessCombo.UpdateLayout(); + if (!this.isQuickAccessFocused) + this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, ((ThreadStart)(() => + { + this.Freeze(); + this.Dispatcher.BeginInvoke(DispatcherPriority.Input, ((ThreadStart)(() => { if (this.quickAccessCombo.SelectedItem != null) (this.quickAccessCombo.ItemContainerGenerator.ContainerFromItem(this.quickAccessCombo.SelectedItem) as ComboBoxItem).BringIntoView(); } + ))); + } + ))); + } + + private void OnQuickAccessMenuClosed(object sender, EventArgs e) + { + this.quickAccessCombo.DropDownClosed -= this.OnQuickAccessMenuClosed; + if (!this.isQuickAccessFocused) this.Unfreeze(); + this.isQuickAccessOpened = false; + } + + private void Freeze() + { + this.IsSnapped = true; + this.selectedItem = this.SelectedItem; + + ItemsControlHelper.MoveItemsToDifferentControl(this, this.quickAccessCombo); + + this.SelectedItem = null; + this.quickAccessCombo.SelectedItem = this.selectedItem; + this.quickAccessCombo.Menu = this.Menu; + this.Menu = null; + this.quickAccessCombo.IsSnapped = false; + } + + private void Unfreeze() + { + var text = this.quickAccessCombo.Text; + this.selectedItem = this.quickAccessCombo.SelectedItem; + this.quickAccessCombo.IsSnapped = true; + + ItemsControlHelper.MoveItemsToDifferentControl(this.quickAccessCombo, this); + + this.quickAccessCombo.SelectedItem = null; + this.SelectedItem = this.selectedItem; + this.Menu = this.quickAccessCombo.Menu; + this.quickAccessCombo.Menu = null; + this.IsSnapped = false; + this.Text = text; + this.UpdateLayout(); + } + + private void UpdateQuickAccessCombo() + { + if (this.IsLoaded == false) + { + this.Loaded += this.OnFirstLoaded; + } + + if (this.IsEditable == false) + { + this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() => + { + this.quickAccessCombo.IsSnapped = true; + this.IsSnapped = true; + if (this.snappedImage != null && + this.quickAccessCombo.snappedImage != null) + { + this.quickAccessCombo.snappedImage.Source = this.snappedImage.Source; + this.quickAccessCombo.snappedImage.Visibility = Visibility.Visible; + if (this.quickAccessCombo.IsSnapped == false) + { + this.quickAccessCombo.isSnapped = true; + } + } + this.IsSnapped = false; + })); + } + } + + private void OnFirstLoaded(object sender, RoutedEventArgs e) + { + this.Loaded -= this.OnFirstLoaded; + this.UpdateQuickAccessCombo(); + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, + /// binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call + /// . + /// + public override void OnApplyTemplate() + { + this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup; + + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; + } + this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; + } + this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; + } + + this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; + + this.snappedImage = this.GetTemplateChild("PART_SelectedImage") as Image; + this.contentSite = this.GetTemplateChild("PART_ContentSite") as ContentPresenter; + + if (this.contentBorder != null) this.contentBorder.PreviewMouseDown -= this.OnContentBorderPreviewMouseDown; + this.contentBorder = this.GetTemplateChild("PART_ContentBorder") as Border; + if (this.contentBorder != null) this.contentBorder.PreviewMouseDown += this.OnContentBorderPreviewMouseDown; + + this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel; + this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; + + this.dropDownBorder = this.GetTemplateChild("PART_DropDownBorder") as Border; + + base.OnApplyTemplate(); + } + + /// + /// Reports when a combo box's popup opens. + /// + /// The event data for the event. + protected override void OnDropDownOpened(EventArgs e) + { + base.OnDropDownOpened(e); + + Mouse.Capture(this, CaptureMode.SubTree); + + if (this.SelectedItem != null) + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); + } + + this.focusedElement = Keyboard.FocusedElement; + + if (this.focusedElement != null) + { + this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; + } + + this.canSizeY = true; + + this.galleryPanel.Width = double.NaN; + this.scrollViewer.Height = double.NaN; + + var popupChild = this.DropDownPopup.Child as FrameworkElement; + var heightDelta = popupChild.DesiredSize.Height - this.scrollViewer.DesiredSize.Height; + + var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height * 2 / 3, this.MaxDropDownHeight); + + if (double.IsNaN(this.DropDownHeight) == false) + { + initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight); + } + + if (this.scrollViewer.DesiredSize.Height > initialHeight) + { + this.scrollViewer.Height = initialHeight; + } + else + { + initialHeight = this.scrollViewer.DesiredSize.Height; + } + + var monitor = RibbonControl.GetControlMonitor(this); + var delta = monitor.Bottom - this.PointToScreen(new Point()).Y - this.ActualHeight - initialHeight - heightDelta; + + if (delta >= 0) + { + this.ShowPopupOnTop = false; + } + else + { + var deltaTop = this.PointToScreen(new Point()).Y - initialHeight - heightDelta - monitor.Top; + + if (deltaTop > delta) + { + this.ShowPopupOnTop = true; + } + else + { + this.ShowPopupOnTop = false; + } + + if (deltaTop < 0) + { + delta = Math.Max(Math.Abs(delta), Math.Abs(deltaTop)); + + if (delta > this.galleryPanel.GetItemSize().Height) + { + this.scrollViewer.Height = delta; + } + else + { + this.canSizeY = false; + this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height; + } + } + } + + popupChild.UpdateLayout(); + } + + /// + /// Reports when a combo box's popup closes. + /// + /// The event data for the event. + protected override void OnDropDownClosed(EventArgs e) + { + base.OnDropDownClosed(e); + if (Mouse.Captured == this) Mouse.Capture(null); + if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; + this.focusedElement = null; + this.ShowPopupOnTop = false; + this.galleryPanel.Width = double.NaN; + this.scrollViewer.Height = double.NaN; + } + + private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; + this.focusedElement = Keyboard.FocusedElement; + if (this.focusedElement != null) + { + this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; + if ((this.IsEditable) && + (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))) + { + this.SelectedItem = this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject); + } + } + } + + /// + /// Invoked when a attached routed event occurs. + /// + /// Event data. + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if ((this.IsEditable) && ((e.Key == Key.Down) || (e.Key == Key.Up)) && (!this.IsDropDownOpen)) + { + this.IsDropDownOpen = true; + e.Handled = true; + return; + } + + base.OnPreviewKeyDown(e); + } + + /// + /// Invoked when a attached routed event occurs. + /// + /// Event data. + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Key == Key.Down) + { + Debug.WriteLine("Down pressed. FocusedElement - " + Keyboard.FocusedElement); + if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) + { + var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); + if (indexOfMSelectedItem != this.Menu.Items.Count - 1) + { + Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem + 1) as IInputElement); + } + else + { + if ((this.Items.Count > 0) && (!this.IsEditable)) + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); + } + else Keyboard.Focus(this.Menu.Items[0] as IInputElement); + } + } + else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) + { + var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); + if (indexOfSelectedItem != this.Items.Count - 1) + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem + 1) as IInputElement); + } + else + { + if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); + else + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); + } + } + } + else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); + e.Handled = true; + Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement); + return; + } + else if (e.Key == Key.Up) + { + Debug.WriteLine("Up pressed. FocusedElement - " + Keyboard.FocusedElement); + if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) + { + var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); + if (indexOfMSelectedItem != 0) + { + Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem - 1) as IInputElement); + } + else + { + if ((this.Items.Count > 0) && (!this.IsEditable)) + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement); + } + else Keyboard.Focus(this.Menu.Items[this.Menu.Items.Count - 1] as IInputElement); + } + } + else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) + { + var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); + if (indexOfSelectedItem != 0) + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem - 1) as IInputElement); + } + else + { + if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(this.Menu.Items.Count - 1) as IInputElement); + else + { + Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement); + } + } + } + else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); + Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement); + e.Handled = true; + return; + } + else if ((e.Key == Key.Return) && (!this.IsEditable) && this.IsDropDownOpen) + { + var element = Keyboard.FocusedElement as DependencyObject; + + // only try to select if we got a focusedElement + if (element != null) + { + var newSelectedIndex = this.ItemContainerGenerator.IndexFromContainer(element); + + // only set the selected index if the focused element was in a container in this combobox + if (newSelectedIndex > -1) + { + this.SelectedIndex = newSelectedIndex; + } + } + } + base.OnKeyDown(e); + } + + #endregion + + #region Methods + + /// + /// Handles key tip pressed + /// + public virtual void OnKeyTipPressed() + { + this.Dispatcher.BeginInvoke( + DispatcherPriority.Normal, + (DispatcherOperationCallback)delegate (object arg) + { + var ctrl = (ComboBox)arg; + + // Edge case: Whole dropdown content is disabled + if (ctrl.IsKeyboardFocusWithin == false) + { + Keyboard.Focus(ctrl); + } + return null; + }, + this); + + if (!this.IsEditable) + { + this.IsDropDownOpen = true; + } + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + + #region Private methods + + // Prevent reopenning of the dropdown menu (popup) + private void OnContentBorderPreviewMouseDown(object sender, MouseButtonEventArgs e) + { + if (this.IsDropDownOpen) + { + this.IsDropDownOpen = false; + e.Handled = true; + } + } + + // Handles resize both drag + private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) + { + // Set height + this.SetDragHeight(e); + + // Set width + this.menuPanel.Width = double.NaN; + if (double.IsNaN(this.galleryPanel.Width)) + { + this.galleryPanel.Width = this.galleryPanel.ActualWidth; + } + + var monitorRight = RibbonControl.GetControlMonitor(this).Right; + var popupChild = this.DropDownPopup.Child as FrameworkElement; + var delta = monitorRight - this.PointToScreen(new Point()).X - popupChild.ActualWidth - e.HorizontalChange; + var deltaX = popupChild.ActualWidth - this.galleryPanel.ActualWidth; + var deltaBorders = this.dropDownBorder.ActualWidth - this.galleryPanel.ActualWidth; + + if (delta > 0) + { + this.galleryPanel.Width = Math.Max(0, Math.Max(this.galleryPanel.Width + e.HorizontalChange, this.ActualWidth - deltaBorders)); + } + else + { + this.galleryPanel.Width = Math.Max(0, Math.Max(monitorRight - this.PointToScreen(new Point()).X - deltaX, this.ActualWidth - deltaBorders)); + } + } + + // Handles resize vertical drag + private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) + { + this.SetDragHeight(e); + } + + private void SetDragHeight(DragDeltaEventArgs e) + { + if (!this.canSizeY) + { + return; + } + + if (double.IsNaN(this.scrollViewer.Height)) + { + this.scrollViewer.Height = this.scrollViewer.ActualHeight; + } + + if (this.ShowPopupOnTop) + { + var monitorTop = RibbonControl.GetControlMonitor(this).Top; + + // Calc shadow height + var delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - e.VerticalChange - monitorTop; + if (delta > 0) + { + this.scrollViewer.Height = Math.Max(0, + Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); + } + else + { + delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - monitorTop; + this.scrollViewer.Height = Math.Max(0, + Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight)); + } + } + else + { + var monitorBottom = RibbonControl.GetControlMonitor(this).Bottom; + var popupChild = this.DropDownPopup.Child as FrameworkElement; + var delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight - e.VerticalChange; + if (delta > 0) + { + this.scrollViewer.Height = Math.Max(0, + Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); + } + else + { + delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight; + this.scrollViewer.Height = Math.Max(0, + Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight)); + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/ContextMenu.cs b/Fluent.Ribbon/Controls/ContextMenu.cs similarity index 91% rename from Fluent/Controls/ContextMenu.cs rename to Fluent.Ribbon/Controls/ContextMenu.cs index 024b67c46..ae6f9960e 100644 --- a/Fluent/Controls/ContextMenu.cs +++ b/Fluent.Ribbon/Controls/ContextMenu.cs @@ -1,165 +1,156 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls.Primitives; - -namespace Fluent -{ - /// - /// Represents context menu resize mode - /// - public enum ContextMenuResizeMode - { - /// - /// Context menu can not be resized - /// - None = 0, - /// - /// Context menu can be only resized vertically - /// - Vertical, - /// - /// Context menu can be resized vertically and horizontally - /// - Both - } - - /// - /// Represents a pop-up menu that enables a control - /// to expose functionality that is specific to the context of the control - /// - public class ContextMenu : System.Windows.Controls.ContextMenu - { - #region Fields - - // Thumb to resize in both directions - Thumb resizeBothThumb; - // Thumb to resize vertical - Thumb resizeVerticalThumb; - - #endregion - - #region Properties - - /// - /// Gets or sets context menu resize mode - /// - public ContextMenuResizeMode ResizeMode - { - get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } - set { this.SetValue(ResizeModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeMode. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeModeProperty = - DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), - typeof(ContextMenu), new UIPropertyMetadata(ContextMenuResizeMode.None)); - - #endregion - - #region Constructor - - /// - /// Static constructor - /// ] - [SuppressMessage("Microsoft.Performance", "CA1810")] - static ContextMenu() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(typeof(ContextMenu))); - FocusVisualStyleProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(null)); - } - - /// - /// Default constructor - /// - public ContextMenu() - { - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; - } - this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; - } - this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; - } - } - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new MenuItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// true if the item is (or is eligible to be) its own container; otherwise, false. - protected override bool IsItemItsOwnContainerOverride(object item) - { - return (item is FrameworkElement); - } - - #endregion - - #region Private methods - - // Handles resize both drag - private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) - { - if (double.IsNaN(this.Width)) - this.Width = this.ActualWidth; - if (double.IsNaN(this.Height)) - this.Height = this.ActualHeight; - this.Width = Math.Max(this.MinWidth, this.Width + e.HorizontalChange); - this.Height = Math.Max(this.MinHeight, this.Height + e.VerticalChange); - } - - // Handles resize vertical drag - private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) - { - if (double.IsNaN(this.Height)) - this.Height = this.ActualHeight; - this.Height = Math.Max(this.MinHeight, this.Height + e.VerticalChange); - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls.Primitives; + +namespace Fluent +{ + /// + /// Represents context menu resize mode + /// + public enum ContextMenuResizeMode + { + /// + /// Context menu can not be resized + /// + None = 0, + /// + /// Context menu can be only resized vertically + /// + Vertical, + /// + /// Context menu can be resized vertically and horizontally + /// + Both + } + + /// + /// Represents a pop-up menu that enables a control + /// to expose functionality that is specific to the context of the control + /// + public class ContextMenu : System.Windows.Controls.ContextMenu + { + #region Fields + + // Thumb to resize in both directions + Thumb resizeBothThumb; + // Thumb to resize vertical + Thumb resizeVerticalThumb; + + #endregion + + #region Properties + + /// + /// Gets or sets context menu resize mode + /// + public ContextMenuResizeMode ResizeMode + { + get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } + set { this.SetValue(ResizeModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeMode. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeModeProperty = + DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), + typeof(ContextMenu), new UIPropertyMetadata(ContextMenuResizeMode.None)); + + #endregion + + #region Constructor + + /// + /// Static constructor + /// ] + [SuppressMessage("Microsoft.Performance", "CA1810")] + static ContextMenu() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(typeof(ContextMenu))); + FocusVisualStyleProperty.OverrideMetadata(typeof(ContextMenu), new FrameworkPropertyMetadata(null)); + } + + /// + /// Default constructor + /// + public ContextMenu() + { + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; + } + this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; + } + this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; + } + } + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new MenuItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// true if the item is (or is eligible to be) its own container; otherwise, false. + protected override bool IsItemItsOwnContainerOverride(object item) + { + return (item is FrameworkElement); + } + + #endregion + + #region Private methods + + // Handles resize both drag + private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) + { + if (double.IsNaN(this.Width)) + this.Width = this.ActualWidth; + if (double.IsNaN(this.Height)) + this.Height = this.ActualHeight; + this.Width = Math.Max(this.MinWidth, this.Width + e.HorizontalChange); + this.Height = Math.Max(this.MinHeight, this.Height + e.VerticalChange); + } + + // Handles resize vertical drag + private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) + { + if (double.IsNaN(this.Height)) + this.Height = this.ActualHeight; + this.Height = Math.Max(this.MinHeight, this.Height + e.VerticalChange); + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/DropDownButton.cs b/Fluent.Ribbon/Controls/DropDownButton.cs similarity index 96% rename from Fluent/Controls/DropDownButton.cs rename to Fluent.Ribbon/Controls/DropDownButton.cs index ed0cfeb90..9285ddf22 100644 --- a/Fluent/Controls/DropDownButton.cs +++ b/Fluent.Ribbon/Controls/DropDownButton.cs @@ -1,922 +1,912 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Collections; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Threading; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Input; - using System.Windows.Markup; - using System.Windows.Threading; - using Fluent.Internal; - - /// - /// Represents drop down button - /// - [ContentProperty("Items")] - [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))] - [TemplatePart(Name = "PART_ResizeBothThumb", Type = typeof(Thumb))] - [TemplatePart(Name = "PART_MenuPanel", Type = typeof(Panel))] - [TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))] - [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] - [TemplatePart(Name = "PART_ButtonBorder", Type = typeof(UIElement))] - public class DropDownButton : MenuBase, IQuickAccessItemProvider, IRibbonControl, IDropDownControl - { - #region Fields - - // Thumb to resize in both directions - private Thumb resizeBothThumb; - - // Thumb to resize vertical - private Thumb resizeVerticalThumb; - - private Panel menuPanel; - - private ScrollViewer scrollViewer; - - private UIElement buttonBorder; - - #endregion - - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(DropDownButton)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(DropDownButton)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(DropDownButton)); - - #endregion - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup { get; private set; } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - private bool HasCapture - { - get - { - return ReferenceEquals(Mouse.Captured, this); - } - } - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(DropDownButton)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(DropDownButton), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var element = (DropDownButton)d; - - var oldElement = e.OldValue as FrameworkElement; - - if (oldElement != null) - { - element.RemoveLogicalChild(oldElement); - } - - var newElement = e.NewValue as FrameworkElement; - - if (newElement != null - && LogicalTreeHelper.GetParent(newElement) == null) - { - element.AddLogicalChild(newElement); - } - } - - #endregion - - #region LargeIcon - - /// - /// Gets or sets button large icon - /// - public object LargeIcon - { - get { return this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(object), - typeof(DropDownButton), new UIPropertyMetadata(null)); - - #endregion - - #region HasTriangle - - /// - /// Gets or sets whether button has triangle - /// - public bool HasTriangle - { - get { return (bool)this.GetValue(HasTriangleProperty); } - set { this.SetValue(HasTriangleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HasTriangle. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasTriangleProperty = - DependencyProperty.Register( - "HasTriangle", typeof(bool), typeof(DropDownButton), new UIPropertyMetadata(true)); - - #endregion - - #region IsDropDownOpen - - /// - /// Gets or sets whether popup is opened - /// - public bool IsDropDownOpen - { - get { return (bool)this.GetValue(IsDropDownOpenProperty); } - set { this.SetValue(IsDropDownOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDropDownOpenProperty = - DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(DropDownButton), - new UIPropertyMetadata(false, OnIsDropDownOpenChanged)); - - #endregion - - #region ResizeMode - - /// - /// Gets or sets context menu resize mode - /// - public ContextMenuResizeMode ResizeMode - { - get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } - set { this.SetValue(ResizeModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeMode. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeModeProperty = - DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), - typeof(DropDownButton), new UIPropertyMetadata(ContextMenuResizeMode.None)); - - #endregion - - #region MaxDropDownHeight - - /// - /// Get or sets max height of drop down popup - /// - public double MaxDropDownHeight - { - get { return (double)this.GetValue(MaxDropDownHeightProperty); } - set { this.SetValue(MaxDropDownHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxDropDownHeightProperty = - DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(DropDownButton), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); - - #endregion - - #region DropDownHeight - - /// - /// Gets or sets initial dropdown height - /// - public double DropDownHeight - { - get { return (double)this.GetValue(DropDownHeightProperty); } - set { this.SetValue(DropDownHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for InitialDropDownHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DropDownHeightProperty = - DependencyProperty.Register("DropDownHeight", typeof(double), typeof(DropDownButton), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ClosePopupOnMouseDown - - /// - /// Gets or sets whether the popup of this drop down button should automatically be closed on mouse down. - /// - public bool ClosePopupOnMouseDown - { - get { return (bool)this.GetValue(ClosePopupOnMouseDownProperty); } - set { this.SetValue(ClosePopupOnMouseDownProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ClosePopupOnMouseDown. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ClosePopupOnMouseDownProperty = - DependencyProperty.Register("ClosePopupOnMouseDown", typeof(bool), typeof(DropDownButton), new PropertyMetadata(false)); - - #endregion - - #region ClosePopupOnMouseDownDelay - - /// - /// Gets or sets the delay in milliseconds to close the popup on mouse down. - /// - public int ClosePopupOnMouseDownDelay - { - get { return (int)this.GetValue(ClosePopupOnMouseDownDelayProperty); } - set { this.SetValue(ClosePopupOnMouseDownDelayProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ClosePopupOnMouseDownDelay. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ClosePopupOnMouseDownDelayProperty = - DependencyProperty.Register("ClosePopupOnMouseDownDelay", typeof(int), typeof(DropDownButton), new PropertyMetadata(150)); - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when context menu is opened - /// - public event EventHandler DropDownOpened; - - /// - /// Occurs when context menu is closed - /// - public event EventHandler DropDownClosed; - - #endregion - - #region Initialize - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static DropDownButton() - { - var type = typeof(DropDownButton); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - - System.Windows.Controls.ToolTipService.IsEnabledProperty.OverrideMetadata(typeof(DropDownButton), new FrameworkPropertyMetadata(null, CoerceToolTipIsEnabled)); - - KeyboardNavigation.ControlTabNavigationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); - KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle)); - - ToolTipService.Attach(type); - PopupService.Attach(type); - ContextMenuService.Attach(type); - } - - /// - /// Default constructor - /// - public DropDownButton() - { - ContextMenuService.Coerce(this); - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.SubscribeEvents(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.UnSubscribeEvents(); - } - - private void SubscribeEvents() - { - // Always unsubscribe events to ensure we don't subscribe twice - this.UnSubscribeEvents(); - - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; - } - - if (this.buttonBorder != null) - { - this.buttonBorder.MouseLeftButtonDown += this.HandleButtonBorderMouseLeftButtonDown; - } - - if (this.DropDownPopup != null) - { - this.DropDownPopup.KeyDown += this.OnDropDownPopupKeyDown; - this.DropDownPopup.AddHandler(MouseDownEvent, new RoutedEventHandler(this.OnDropDownPopupMouseDown), true); - } - } - - private void UnSubscribeEvents() - { - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; - } - - if (this.buttonBorder != null) - { - this.buttonBorder.MouseLeftButtonDown -= this.HandleButtonBorderMouseLeftButtonDown; - } - - if (this.DropDownPopup != null) - { - this.DropDownPopup.KeyDown -= this.OnDropDownPopupKeyDown; - this.DropDownPopup.RemoveHandler(MouseDownEvent, new RoutedEventHandler(this.OnDropDownPopupMouseDown)); - } - } - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - this.UnSubscribeEvents(); - - this.DropDownPopup = this.Template.FindName("PART_Popup", this) as Popup; - - if (this.DropDownPopup != null) - { - KeyboardNavigation.SetDirectionalNavigation(this.DropDownPopup, KeyboardNavigationMode.Cycle); - KeyboardNavigation.SetTabNavigation(this.DropDownPopup, KeyboardNavigationMode.Continue); - } - - this.resizeVerticalThumb = this.Template.FindName("PART_ResizeVerticalThumb", this) as Thumb; - - this.resizeBothThumb = this.Template.FindName("PART_ResizeBothThumb", this) as Thumb; - - this.menuPanel = this.Template.FindName("PART_MenuPanel", this) as Panel; - - this.scrollViewer = this.Template.FindName("PART_ScrollViewer", this) as ScrollViewer; - - this.buttonBorder = this.Template.FindName("PART_ButtonBorder", this) as UIElement; - - base.OnApplyTemplate(); - - this.SubscribeEvents(); - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new MenuItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is FrameworkElement; - } - - private void OnDropDownPopupKeyDown(object sender, KeyEventArgs e) - { - if (e.Handled) - { - return; - } - - var handled = false; - - switch (e.Key) - { - case Key.Escape: - this.IsDropDownOpen = false; - handled = true; - break; - } - - if (handled) - { - e.Handled = true; - } - } - - private void OnDropDownPopupMouseDown(object sender, RoutedEventArgs e) - { - if (this.ClosePopupOnMouseDown - && this.resizeBothThumb.IsMouseOver == false - && this.resizeVerticalThumb.IsMouseOver == false) - { - e.Handled = false; - - // Note: get outside thread to prevent exceptions (it's a dependency property after all) - var closePopupOnMouseDownDelay = this.ClosePopupOnMouseDownDelay; - - // Ugly workaround, but use a timer to allow routed event to continue - System.Threading.Tasks.Task.Factory.StartNew(() => - { - Thread.Sleep(closePopupOnMouseDownDelay); - - this.Dispatcher.BeginInvoke(new Action(() => this.IsDropDownOpen = false)); - }); - } - } - - private void HandleButtonBorderMouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - e.Handled = true; - - this.Focus(); - this.IsDropDownOpen = !this.IsDropDownOpen; - } - - /// - /// Provides class handling for the routed event that occurs when the user presses a key. - /// - /// The event data for the event. - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.Handled) - { - return; - } - - var handled = false; - - switch (e.Key) - { - case Key.Down: - if (this.HasItems - && this.IsDropDownOpen == false) // Only handle this for initial navigation. Further navigation is handled by the dropdown itself - { - this.IsDropDownOpen = true; - - var container = this.ItemContainerGenerator.ContainerFromIndex(0); - - NavigateToContainer(container); - - handled = true; - } - break; - - case Key.Up: - if (this.HasItems - && this.IsDropDownOpen == false) // Only handle this for initial navigation. Further navigation is handled by the dropdown itself - { - this.IsDropDownOpen = true; - - var container = this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1); - - NavigateToContainer(container); - - handled = true; - } - break; - - case Key.Escape: - if (this.IsDropDownOpen) - { - this.IsDropDownOpen = false; - handled = true; - } - break; - - case Key.Enter: - case Key.Space: - this.IsDropDownOpen = !this.IsDropDownOpen; - handled = true; - break; - } - - if (handled) - { - e.Handled = true; - } - } - - private static void NavigateToContainer(DependencyObject container) - { - var element = container as FrameworkElement; - - if (element == null) - { - return; - } - - if (element.Focusable) - { - Keyboard.Focus(element); - } - else - { - var predicted = element.PredictFocus(FocusNavigationDirection.Down); - - if (predicted is MenuBase == false) - { - element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down)); - } - } - } - - private static object CoerceToolTipIsEnabled(DependencyObject d, object basevalue) - { - var control = (DropDownButton)d; - - return !control.IsDropDownOpen; - } - - #endregion - - #region Methods - - /// - /// Handles key tip pressed - /// - public virtual void OnKeyTipPressed() - { - this.IsDropDownOpen = true; - - if (this.DropDownPopup != null - && this.DropDownPopup.Child != null) - { - Keyboard.Focus(this.DropDownPopup.Child); - this.DropDownPopup.Child.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); - } - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - this.IsDropDownOpen = false; - } - - #endregion - - #region Private methods - - // Handles resize both drag - private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) - { - if (this.scrollViewer == null) - { - return; - } - - if (double.IsNaN(this.scrollViewer.Width)) - { - this.scrollViewer.Width = this.scrollViewer.ActualWidth; - } - - if (double.IsNaN(this.scrollViewer.Height)) - { - this.scrollViewer.Height = this.scrollViewer.ActualHeight; - } - - this.scrollViewer.Width = Math.Max(this.ActualWidth, this.scrollViewer.Width + e.HorizontalChange); - this.scrollViewer.Height = Math.Min(Math.Max(this.ActualHeight, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight); - } - - // Handles resize vertical drag - private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) - { - if (this.scrollViewer == null) - { - return; - } - - if (double.IsNaN(this.scrollViewer.Height)) - { - this.scrollViewer.Height = this.scrollViewer.ActualHeight; - } - - this.scrollViewer.Height = Math.Min(Math.Max(this.ActualHeight, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight); - } - - private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = (DropDownButton)d; - - var newValue = (bool)e.NewValue; - - control.SetValue(System.Windows.Controls.ToolTipService.IsEnabledProperty, !newValue); - - Debug.WriteLine(string.Format("{0} IsDropDownOpen: {1}", control.Header, newValue)); - - if (newValue) - { - Mouse.Capture(control, CaptureMode.SubTree); - - Keyboard.Focus(control.DropDownPopup); - - control.Dispatcher.BeginInvoke( - DispatcherPriority.Normal, - (DispatcherOperationCallback)delegate(object arg) - { - var ctrl = (DropDownButton)arg; - - var container = ctrl.ItemContainerGenerator.ContainerFromIndex(0); - - NavigateToContainer(container); - - // Edge case: Whole dropdown content is disabled - if (ctrl.IsKeyboardFocusWithin == false) - { - Keyboard.Focus(ctrl.DropDownPopup); - } - - return null; - }, - control); - - control.OnDropDownOpened(); - } - else - { - // If focus is within the subtree, make sure we have the focus so that focus isn't in the disposed hwnd - if (control.IsKeyboardFocusWithin) - { - // make sure the control has focus - control.Focus(); - } - - Mouse.Capture(null); - - control.OnDropDownClosed(); - } - } - - // Handles drop down closed - private void OnDropDownClosed() - { - if (this.DropDownClosed != null) - { - this.DropDownClosed(this, EventArgs.Empty); - } - } - - // Handles drop down opened - private void OnDropDownOpened() - { - if (this.DropDownOpened != null) - { - this.DropDownOpened(this, EventArgs.Empty); - } - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be synchronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - var button = new DropDownButton - { - Size = RibbonControlSize.Small - }; - - this.BindQuickAccessItem(button); - RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - - RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); - - this.BindQuickAccessItemDropDownEvents(button); - - button.DropDownOpened += this.OnQuickAccessOpened; - return button; - } - - /// - /// Handles quick access button drop down menu opened - /// - /// - /// - protected void OnQuickAccessOpened(object sender, EventArgs e) - { - var buttonInQuickAccess = (DropDownButton)sender; - - buttonInQuickAccess.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; - buttonInQuickAccess.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; - - ItemsControlHelper.MoveItemsToDifferentControl(this, buttonInQuickAccess); - } - - /// - /// Handles quick access button drop down menu closed - /// - /// - /// - protected void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) - { - var buttonInQuickAccess = (DropDownButton)sender; - buttonInQuickAccess.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; - buttonInQuickAccess.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; - this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (Action)(() => - { - ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); - })); - } - - /// - /// This method must be overridden to bind properties to use in quick access creating - /// - /// Toolbar item - protected virtual void BindQuickAccessItem(FrameworkElement element) - { - RibbonControl.BindQuickAccessItem(this, element); - RibbonControl.Bind(this, element, "ResizeMode", ResizeModeProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "HasTriangle", HasTriangleProperty, BindingMode.Default); - } - - /// - /// Binds the DropDownClosed and DropDownOpened events to the created quick access item - /// - /// Toolbar item - protected void BindQuickAccessItemDropDownEvents(DropDownButton button) - { - if (this.DropDownClosed != null) button.DropDownClosed += this.DropDownClosed; - if (this.DropDownOpened != null) button.DropDownOpened += this.DropDownOpened; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(DropDownButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - /// - /// Gets an enumerator for the logical child objects of the object. - /// - /// - /// An enumerator for the logical child objects of the object. The default is null. - /// - protected override IEnumerator LogicalChildren - { - get - { - if (this.Icon != null) - { - yield return this.Icon; - } - - foreach (var item in this.Items) - { - yield return item; - } - } - } - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Threading; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Markup; + using System.Windows.Threading; + using Fluent.Internal; + + /// + /// Represents drop down button + /// + [ContentProperty("Items")] + [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))] + [TemplatePart(Name = "PART_ResizeBothThumb", Type = typeof(Thumb))] + [TemplatePart(Name = "PART_MenuPanel", Type = typeof(Panel))] + [TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))] + [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] + [TemplatePart(Name = "PART_ButtonBorder", Type = typeof(UIElement))] + public class DropDownButton : MenuBase, IQuickAccessItemProvider, IRibbonControl, IDropDownControl + { + #region Fields + + // Thumb to resize in both directions + private Thumb resizeBothThumb; + + // Thumb to resize vertical + private Thumb resizeVerticalThumb; + + private Panel menuPanel; + + private ScrollViewer scrollViewer; + + private UIElement buttonBorder; + + #endregion + + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(DropDownButton)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(DropDownButton)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(DropDownButton)); + + #endregion + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup { get; private set; } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + private bool HasCapture + { + get + { + return ReferenceEquals(Mouse.Captured, this); + } + } + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(DropDownButton)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(DropDownButton), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = (DropDownButton)d; + + var oldElement = e.OldValue as FrameworkElement; + + if (oldElement != null) + { + element.RemoveLogicalChild(oldElement); + } + + var newElement = e.NewValue as FrameworkElement; + + if (newElement != null + && LogicalTreeHelper.GetParent(newElement) == null) + { + element.AddLogicalChild(newElement); + } + } + + #endregion + + #region LargeIcon + + /// + /// Gets or sets button large icon + /// + public object LargeIcon + { + get { return this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = + DependencyProperty.Register("LargeIcon", typeof(object), + typeof(DropDownButton), new UIPropertyMetadata(null)); + + #endregion + + #region HasTriangle + + /// + /// Gets or sets whether button has triangle + /// + public bool HasTriangle + { + get { return (bool)this.GetValue(HasTriangleProperty); } + set { this.SetValue(HasTriangleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HasTriangle. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasTriangleProperty = + DependencyProperty.Register( + "HasTriangle", typeof(bool), typeof(DropDownButton), new UIPropertyMetadata(true)); + + #endregion + + #region IsDropDownOpen + + /// + /// Gets or sets whether popup is opened + /// + public bool IsDropDownOpen + { + get { return (bool)this.GetValue(IsDropDownOpenProperty); } + set { this.SetValue(IsDropDownOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDropDownOpenProperty = + DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(DropDownButton), + new UIPropertyMetadata(false, OnIsDropDownOpenChanged)); + + #endregion + + #region ResizeMode + + /// + /// Gets or sets context menu resize mode + /// + public ContextMenuResizeMode ResizeMode + { + get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } + set { this.SetValue(ResizeModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeMode. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeModeProperty = + DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), + typeof(DropDownButton), new UIPropertyMetadata(ContextMenuResizeMode.None)); + + #endregion + + #region MaxDropDownHeight + + /// + /// Get or sets max height of drop down popup + /// + public double MaxDropDownHeight + { + get { return (double)this.GetValue(MaxDropDownHeightProperty); } + set { this.SetValue(MaxDropDownHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxDropDownHeightProperty = + DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(DropDownButton), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); + + #endregion + + #region DropDownHeight + + /// + /// Gets or sets initial dropdown height + /// + public double DropDownHeight + { + get { return (double)this.GetValue(DropDownHeightProperty); } + set { this.SetValue(DropDownHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for InitialDropDownHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DropDownHeightProperty = + DependencyProperty.Register("DropDownHeight", typeof(double), typeof(DropDownButton), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ClosePopupOnMouseDown + + /// + /// Gets or sets whether the popup of this drop down button should automatically be closed on mouse down. + /// + public bool ClosePopupOnMouseDown + { + get { return (bool)this.GetValue(ClosePopupOnMouseDownProperty); } + set { this.SetValue(ClosePopupOnMouseDownProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ClosePopupOnMouseDown. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ClosePopupOnMouseDownProperty = + DependencyProperty.Register("ClosePopupOnMouseDown", typeof(bool), typeof(DropDownButton), new PropertyMetadata(false)); + + #endregion + + #region ClosePopupOnMouseDownDelay + + /// + /// Gets or sets the delay in milliseconds to close the popup on mouse down. + /// + public int ClosePopupOnMouseDownDelay + { + get { return (int)this.GetValue(ClosePopupOnMouseDownDelayProperty); } + set { this.SetValue(ClosePopupOnMouseDownDelayProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ClosePopupOnMouseDownDelay. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ClosePopupOnMouseDownDelayProperty = + DependencyProperty.Register("ClosePopupOnMouseDownDelay", typeof(int), typeof(DropDownButton), new PropertyMetadata(150)); + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when context menu is opened + /// + public event EventHandler DropDownOpened; + + /// + /// Occurs when context menu is closed + /// + public event EventHandler DropDownClosed; + + #endregion + + #region Initialize + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static DropDownButton() + { + var type = typeof(DropDownButton); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + + System.Windows.Controls.ToolTipService.IsEnabledProperty.OverrideMetadata(typeof(DropDownButton), new FrameworkPropertyMetadata(null, CoerceToolTipIsEnabled)); + + KeyboardNavigation.ControlTabNavigationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); + KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle)); + + ToolTipService.Attach(type); + PopupService.Attach(type); + ContextMenuService.Attach(type); + } + + /// + /// Default constructor + /// + public DropDownButton() + { + ContextMenuService.Coerce(this); + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.SubscribeEvents(); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.UnSubscribeEvents(); + } + + private void SubscribeEvents() + { + // Always unsubscribe events to ensure we don't subscribe twice + this.UnSubscribeEvents(); + + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; + } + + if (this.buttonBorder != null) + { + this.buttonBorder.MouseLeftButtonDown += this.HandleButtonBorderMouseLeftButtonDown; + } + + if (this.DropDownPopup != null) + { + this.DropDownPopup.KeyDown += this.OnDropDownPopupKeyDown; + this.DropDownPopup.AddHandler(MouseDownEvent, new RoutedEventHandler(this.OnDropDownPopupMouseDown), true); + } + } + + private void UnSubscribeEvents() + { + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; + } + + if (this.buttonBorder != null) + { + this.buttonBorder.MouseLeftButtonDown -= this.HandleButtonBorderMouseLeftButtonDown; + } + + if (this.DropDownPopup != null) + { + this.DropDownPopup.KeyDown -= this.OnDropDownPopupKeyDown; + this.DropDownPopup.RemoveHandler(MouseDownEvent, new RoutedEventHandler(this.OnDropDownPopupMouseDown)); + } + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + this.UnSubscribeEvents(); + + this.DropDownPopup = this.Template.FindName("PART_Popup", this) as Popup; + + if (this.DropDownPopup != null) + { + KeyboardNavigation.SetDirectionalNavigation(this.DropDownPopup, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetTabNavigation(this.DropDownPopup, KeyboardNavigationMode.Continue); + } + + this.resizeVerticalThumb = this.Template.FindName("PART_ResizeVerticalThumb", this) as Thumb; + + this.resizeBothThumb = this.Template.FindName("PART_ResizeBothThumb", this) as Thumb; + + this.menuPanel = this.Template.FindName("PART_MenuPanel", this) as Panel; + + this.scrollViewer = this.Template.FindName("PART_ScrollViewer", this) as ScrollViewer; + + this.buttonBorder = this.Template.FindName("PART_ButtonBorder", this) as UIElement; + + base.OnApplyTemplate(); + + this.SubscribeEvents(); + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new MenuItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is FrameworkElement; + } + + private void OnDropDownPopupKeyDown(object sender, KeyEventArgs e) + { + if (e.Handled) + { + return; + } + + var handled = false; + + switch (e.Key) + { + case Key.Escape: + this.IsDropDownOpen = false; + handled = true; + break; + } + + if (handled) + { + e.Handled = true; + } + } + + private void OnDropDownPopupMouseDown(object sender, RoutedEventArgs e) + { + if (this.ClosePopupOnMouseDown + && this.resizeBothThumb.IsMouseOver == false + && this.resizeVerticalThumb.IsMouseOver == false) + { + e.Handled = false; + + // Note: get outside thread to prevent exceptions (it's a dependency property after all) + var closePopupOnMouseDownDelay = this.ClosePopupOnMouseDownDelay; + + // Ugly workaround, but use a timer to allow routed event to continue + System.Threading.Tasks.Task.Factory.StartNew(() => + { + Thread.Sleep(closePopupOnMouseDownDelay); + + this.Dispatcher.BeginInvoke(new Action(() => this.IsDropDownOpen = false)); + }); + } + } + + private void HandleButtonBorderMouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + e.Handled = true; + + this.Focus(); + this.IsDropDownOpen = !this.IsDropDownOpen; + } + + /// + /// Provides class handling for the routed event that occurs when the user presses a key. + /// + /// The event data for the event. + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Handled) + { + return; + } + + var handled = false; + + switch (e.Key) + { + case Key.Down: + if (this.HasItems + && this.IsDropDownOpen == false) // Only handle this for initial navigation. Further navigation is handled by the dropdown itself + { + this.IsDropDownOpen = true; + + var container = this.ItemContainerGenerator.ContainerFromIndex(0); + + NavigateToContainer(container); + + handled = true; + } + break; + + case Key.Up: + if (this.HasItems + && this.IsDropDownOpen == false) // Only handle this for initial navigation. Further navigation is handled by the dropdown itself + { + this.IsDropDownOpen = true; + + var container = this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1); + + NavigateToContainer(container); + + handled = true; + } + break; + + case Key.Escape: + if (this.IsDropDownOpen) + { + this.IsDropDownOpen = false; + handled = true; + } + break; + + case Key.Enter: + case Key.Space: + this.IsDropDownOpen = !this.IsDropDownOpen; + handled = true; + break; + } + + if (handled) + { + e.Handled = true; + } + } + + private static void NavigateToContainer(DependencyObject container) + { + var element = container as FrameworkElement; + + if (element == null) + { + return; + } + + if (element.Focusable) + { + Keyboard.Focus(element); + } + else + { + var predicted = element.PredictFocus(FocusNavigationDirection.Down); + + if (predicted is MenuBase == false) + { + element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down)); + } + } + } + + private static object CoerceToolTipIsEnabled(DependencyObject d, object basevalue) + { + var control = (DropDownButton)d; + + return !control.IsDropDownOpen; + } + + #endregion + + #region Methods + + /// + /// Handles key tip pressed + /// + public virtual void OnKeyTipPressed() + { + this.IsDropDownOpen = true; + + if (this.DropDownPopup != null + && this.DropDownPopup.Child != null) + { + Keyboard.Focus(this.DropDownPopup.Child); + this.DropDownPopup.Child.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); + } + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + this.IsDropDownOpen = false; + } + + #endregion + + #region Private methods + + // Handles resize both drag + private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) + { + if (this.scrollViewer == null) + { + return; + } + + if (double.IsNaN(this.scrollViewer.Width)) + { + this.scrollViewer.Width = this.scrollViewer.ActualWidth; + } + + if (double.IsNaN(this.scrollViewer.Height)) + { + this.scrollViewer.Height = this.scrollViewer.ActualHeight; + } + + this.scrollViewer.Width = Math.Max(this.ActualWidth, this.scrollViewer.Width + e.HorizontalChange); + this.scrollViewer.Height = Math.Min(Math.Max(this.ActualHeight, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight); + } + + // Handles resize vertical drag + private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) + { + if (this.scrollViewer == null) + { + return; + } + + if (double.IsNaN(this.scrollViewer.Height)) + { + this.scrollViewer.Height = this.scrollViewer.ActualHeight; + } + + this.scrollViewer.Height = Math.Min(Math.Max(this.ActualHeight, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight); + } + + private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (DropDownButton)d; + + var newValue = (bool)e.NewValue; + + control.SetValue(System.Windows.Controls.ToolTipService.IsEnabledProperty, !newValue); + + Debug.WriteLine(string.Format("{0} IsDropDownOpen: {1}", control.Header, newValue)); + + if (newValue) + { + Mouse.Capture(control, CaptureMode.SubTree); + + Keyboard.Focus(control.DropDownPopup); + + control.Dispatcher.BeginInvoke( + DispatcherPriority.Normal, + (DispatcherOperationCallback)delegate(object arg) + { + var ctrl = (DropDownButton)arg; + + var container = ctrl.ItemContainerGenerator.ContainerFromIndex(0); + + NavigateToContainer(container); + + // Edge case: Whole dropdown content is disabled + if (ctrl.IsKeyboardFocusWithin == false) + { + Keyboard.Focus(ctrl.DropDownPopup); + } + + return null; + }, + control); + + control.OnDropDownOpened(); + } + else + { + // If focus is within the subtree, make sure we have the focus so that focus isn't in the disposed hwnd + if (control.IsKeyboardFocusWithin) + { + // make sure the control has focus + control.Focus(); + } + + Mouse.Capture(null); + + control.OnDropDownClosed(); + } + } + + // Handles drop down closed + private void OnDropDownClosed() + { + if (this.DropDownClosed != null) + { + this.DropDownClosed(this, EventArgs.Empty); + } + } + + // Handles drop down opened + private void OnDropDownOpened() + { + if (this.DropDownOpened != null) + { + this.DropDownOpened(this, EventArgs.Empty); + } + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be synchronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + var button = new DropDownButton + { + Size = RibbonControlSize.Small + }; + + this.BindQuickAccessItem(button); + RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + + RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); + + this.BindQuickAccessItemDropDownEvents(button); + + button.DropDownOpened += this.OnQuickAccessOpened; + return button; + } + + /// + /// Handles quick access button drop down menu opened + /// + /// + /// + protected void OnQuickAccessOpened(object sender, EventArgs e) + { + var buttonInQuickAccess = (DropDownButton)sender; + + buttonInQuickAccess.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; + buttonInQuickAccess.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; + + ItemsControlHelper.MoveItemsToDifferentControl(this, buttonInQuickAccess); + } + + /// + /// Handles quick access button drop down menu closed + /// + /// + /// + protected void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) + { + var buttonInQuickAccess = (DropDownButton)sender; + buttonInQuickAccess.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; + buttonInQuickAccess.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; + this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (Action)(() => + { + ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); + })); + } + + /// + /// This method must be overridden to bind properties to use in quick access creating + /// + /// Toolbar item + protected virtual void BindQuickAccessItem(FrameworkElement element) + { + RibbonControl.BindQuickAccessItem(this, element); + RibbonControl.Bind(this, element, "ResizeMode", ResizeModeProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "HasTriangle", HasTriangleProperty, BindingMode.Default); + } + + /// + /// Binds the DropDownClosed and DropDownOpened events to the created quick access item + /// + /// Toolbar item + protected void BindQuickAccessItemDropDownEvents(DropDownButton button) + { + if (this.DropDownClosed != null) button.DropDownClosed += this.DropDownClosed; + if (this.DropDownOpened != null) button.DropDownOpened += this.DropDownOpened; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(DropDownButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + /// + /// Gets an enumerator for the logical child objects of the object. + /// + /// + /// An enumerator for the logical child objects of the object. The default is null. + /// + protected override IEnumerator LogicalChildren + { + get + { + if (this.Icon != null) + { + yield return this.Icon; + } + + foreach (var item in this.Items) + { + yield return item; + } + } + } + } } \ No newline at end of file diff --git a/Fluent/Controls/Gallery.cs b/Fluent.Ribbon/Controls/Gallery.cs similarity index 95% rename from Fluent/Controls/Gallery.cs rename to Fluent.Ribbon/Controls/Gallery.cs index a3e0925f5..f34f23ab1 100644 --- a/Fluent/Controls/Gallery.cs +++ b/Fluent.Ribbon/Controls/Gallery.cs @@ -1,542 +1,533 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Markup; - -namespace Fluent -{ - // TODO: add TemplatePart's in Gallery (!) - - /// - /// Represents gallery control. - /// Usually a gallery is hosted in context menu - /// - [ContentProperty("Items")] - public class Gallery : ListBox - { - #region Fields - - private ObservableCollection filters; - - private DropDownButton groupsMenuButton; - - #endregion - - #region Properties - - #region MinItemsInRow - - /// - /// Min width of the Gallery - /// - public int MinItemsInRow - { - get { return (int)this.GetValue(MinItemsInRowProperty); } - set { this.SetValue(MinItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MinItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinItemsInRowProperty = - DependencyProperty.Register("MinItemsInRow", typeof(int), - typeof(Gallery), new UIPropertyMetadata(1)); - - #endregion - - #region MaxItemsInRow - - /// - /// Max width of the Gallery - /// - public int MaxItemsInRow - { - get { return (int)this.GetValue(MaxItemsInRowProperty); } - set { this.SetValue(MaxItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxItemsInRowProperty = - DependencyProperty.Register("MaxItemsInRow", typeof(int), - typeof(Gallery), new UIPropertyMetadata(int.MaxValue)); - - #endregion - - #region GroupBy - - /// - /// Gets or sets name of property which - /// will use to group items in the Gallery. - /// - public string GroupBy - { - get { return (string)this.GetValue(GroupByProperty); } - set { this.SetValue(GroupByProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupBy. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupByProperty = - DependencyProperty.Register("GroupBy", typeof(string), typeof(Gallery), - new UIPropertyMetadata(null)); - - #endregion - - #region Orientation - - /// - /// Gets or sets orientation of gallery - /// - public Orientation Orientation - { - get { return (Orientation)this.GetValue(OrientationProperty); } - set { this.SetValue(OrientationProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Orientation. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty OrientationProperty = - DependencyProperty.Register("Orientation", typeof(Orientation), - typeof(Gallery), new UIPropertyMetadata(Orientation.Horizontal)); - - #endregion - - #region ItemWidth - - /// - /// Gets or sets item width - /// - public double ItemWidth - { - get { return (double)this.GetValue(ItemWidthProperty); } - set { this.SetValue(ItemWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemWidthProperty = - DependencyProperty.Register("ItemWidth", typeof(double), typeof(Gallery), new UIPropertyMetadata(double.NaN)); - - /// - /// Gets or sets item height - /// - public double ItemHeight - { - get { return (double)this.GetValue(ItemHeightProperty); } - set { this.SetValue(ItemHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), typeof(Gallery), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region Filters - - /// - /// Gets collection of filters - /// - public ObservableCollection Filters - { - get - { - if (this.filters == null) - { - this.filters = new ObservableCollection(); - this.filters.CollectionChanged += this.OnFilterCollectionChanged; - } - return this.filters; - } - } - - // Handle toolbar items changes - void OnFilterCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.HasFilter = this.Filters.Count > 0; - this.InvalidateProperty(SelectedFilterProperty); - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (int i = 0; i < e.NewItems.Count; i++) - { - if (this.groupsMenuButton != null) - { - GalleryGroupFilter filter = (GalleryGroupFilter)e.NewItems[i]; - MenuItem menuItem = new MenuItem(); - menuItem.Header = filter.Title; - menuItem.Tag = filter; - if (filter == this.SelectedFilter) menuItem.IsChecked = true; - menuItem.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Insert(e.NewStartingIndex + i, menuItem); - } - } - break; - case NotifyCollectionChangedAction.Remove: - foreach (object item in e.OldItems) - { - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item as GalleryGroupFilter)); - } - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (object item in e.OldItems) - { - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item as GalleryGroupFilter)); - } - } - foreach (var item in e.NewItems.OfType()) - { - if (this.groupsMenuButton != null) - { - GalleryGroupFilter filter = item; - MenuItem menuItem = new MenuItem(); - menuItem.Header = filter.Title; - menuItem.Tag = filter; - if (filter == this.SelectedFilter) menuItem.IsChecked = true; - menuItem.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Add(menuItem); - } - } - break; - } - } - - /// - /// Gets or sets selected filter - /// - public GalleryGroupFilter SelectedFilter - { - get { return (GalleryGroupFilter)this.GetValue(SelectedFilterProperty); } - set { this.SetValue(SelectedFilterProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectedFilter. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterProperty = - DependencyProperty.Register("SelectedFilter", typeof(GalleryGroupFilter), - typeof(Gallery), new UIPropertyMetadata(null, OnFilterChanged, CoerceSelectedFilter)); - - // Coerce selected filter - static object CoerceSelectedFilter(DependencyObject d, object basevalue) - { - Gallery gallery = (Gallery)d; - if ((basevalue == null) && (gallery.Filters.Count > 0)) return gallery.Filters[0]; - return basevalue; - } - - // Handles filter property changed - static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - Gallery gallery = (Gallery)d; - GalleryGroupFilter filter = e.NewValue as GalleryGroupFilter; - if (filter != null) - { - gallery.SelectedFilterTitle = filter.Title; - gallery.SelectedFilterGroups = filter.Groups; - } - else - { - gallery.SelectedFilterTitle = ""; - gallery.SelectedFilterGroups = null; - } - gallery.UpdateLayout(); - } - - /// - /// Gets selected filter title - /// - public string SelectedFilterTitle - { - get { return (string)this.GetValue(SelectedFilterTitleProperty); } - private set { this.SetValue(SelectedFilterTitlePropertyKey, value); } - } - - private static readonly DependencyPropertyKey SelectedFilterTitlePropertyKey = - DependencyProperty.RegisterReadOnly("SelectedFilterTitle", typeof(string), - typeof(Gallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for SelectedFilterTitle. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterTitleProperty = SelectedFilterTitlePropertyKey.DependencyProperty; - - /// - /// Gets selected filter groups - /// - public string SelectedFilterGroups - { - get { return (string)this.GetValue(SelectedFilterGroupsProperty); } - private set { this.SetValue(SelectedFilterGroupsPropertyKey, value); } - } - - private static readonly DependencyPropertyKey SelectedFilterGroupsPropertyKey = - DependencyProperty.RegisterReadOnly("SelectedFilterGroups", typeof(string), - typeof(Gallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for SelectedFilterGroups. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterGroupsProperty = SelectedFilterGroupsPropertyKey.DependencyProperty; - - /// - /// Gets whether gallery has selected filter - /// - public bool HasFilter - { - get { return (bool)this.GetValue(HasFilterProperty); } - private set { this.SetValue(HasFilterPropertyKey, value); } - } - - private static readonly DependencyPropertyKey HasFilterPropertyKey = DependencyProperty.RegisterReadOnly("HasFilter", typeof(bool), typeof(Gallery), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for HasFilter. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasFilterProperty = HasFilterPropertyKey.DependencyProperty; - - void OnFilterMenuItemClick(object sender, RoutedEventArgs e) - { - MenuItem senderItem = (MenuItem)sender; - MenuItem item = this.GetFilterMenuItem(this.SelectedFilter); - item.IsChecked = false; - senderItem.IsChecked = true; - this.SelectedFilter = senderItem.Tag as GalleryGroupFilter; - this.groupsMenuButton.IsDropDownOpen = false; - e.Handled = true; - } - - MenuItem GetFilterMenuItem(GalleryGroupFilter filter) - { - if (filter == null) return null; - return this.groupsMenuButton.Items.Cast().FirstOrDefault(item => (item != null) && (item.Header.ToString() == filter.Title)); - /*foreach (MenuItem item in groupsMenuButton.Items) - { - if ((item!=null)&&(item.Header == filter.Title)) return item; - } - return null;*/ - } - - #endregion - - #region Selectable - - /// - /// Gets or sets whether gallery items can be selected - /// - public bool Selectable - { - get { return (bool)this.GetValue(SelectableProperty); } - set { this.SetValue(SelectableProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Selectable. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectableProperty = - DependencyProperty.Register("Selectable", typeof(bool), - typeof(Gallery), new UIPropertyMetadata(true, OnSelectableChanged)); - - private static void OnSelectableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - d.CoerceValue(SelectedItemProperty); - } - - #endregion - - #region IsLastItem - - /// - /// Gets whether gallery is last item in ItemsControl - /// - public bool IsLastItem - { - get { return (bool)this.GetValue(IsLastItemProperty); } - private set { this.SetValue(IsLastItemPropertyKey, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsLastItem. This enables animation, styling, binding, etc... - /// - public static readonly DependencyPropertyKey IsLastItemPropertyKey = DependencyProperty.RegisterReadOnly("IsLastItem", typeof(bool), typeof(Gallery), new UIPropertyMetadata(false)); - /// - /// Using a DependencyProperty as the backing store for IsLastItem. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsLastItemProperty = IsLastItemPropertyKey.DependencyProperty; - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static Gallery() - { - Type type = typeof(Gallery); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(typeof(Gallery))); - SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, CoerceSelectedItem)); - ContextMenuService.Attach(type); - StyleProperty.OverrideMetadata(typeof(Gallery), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(Gallery)); - } - - return basevalue; - } - - // Coerce selected item - private static object CoerceSelectedItem(DependencyObject d, object basevalue) - { - Gallery gallery = (Gallery)d; - - if (!gallery.Selectable) - { - GalleryItem galleryItem = (GalleryItem)gallery.ItemContainerGenerator.ContainerFromItem(basevalue); - - if (basevalue != null && galleryItem != null) - { - galleryItem.IsSelected = false; - } - - return null; - } - - return basevalue; - } - - /// - /// Default constructor - /// - public Gallery() - { - ContextMenuService.Coerce(this); - this.Loaded += this.OnLoaded; - this.Focusable = false; - KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Continue); - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - ItemsControl parent = this.Parent as ItemsControl; - if (parent != null) - { - if (parent.Items.IndexOf(this) == parent.Items.Count - 1) - { - this.IsLastItem = true; - } - else - { - this.IsLastItem = false; - } - } - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new GalleryItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is GalleryItem; - } - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Clear(); - } - - this.groupsMenuButton = this.GetTemplateChild("PART_DropDownButton") as DropDownButton; - - if (this.groupsMenuButton != null) - { - for (int i = 0; i < this.Filters.Count; i++) - { - var item = new MenuItem - { - Header = this.Filters[i].Title, - Tag = this.Filters[i], - IsDefinitive = false - }; - - if (this.Filters[i] == this.SelectedFilter) - { - item.IsChecked = true; - } - - item.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Add(item); - } - } - - base.OnApplyTemplate(); - } - - #endregion - } +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Markup; + +namespace Fluent +{ + // TODO: add TemplatePart's in Gallery (!) + + /// + /// Represents gallery control. + /// Usually a gallery is hosted in context menu + /// + [ContentProperty("Items")] + public class Gallery : ListBox + { + #region Fields + + private ObservableCollection filters; + + private DropDownButton groupsMenuButton; + + #endregion + + #region Properties + + #region MinItemsInRow + + /// + /// Min width of the Gallery + /// + public int MinItemsInRow + { + get { return (int)this.GetValue(MinItemsInRowProperty); } + set { this.SetValue(MinItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MinItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinItemsInRowProperty = + DependencyProperty.Register("MinItemsInRow", typeof(int), + typeof(Gallery), new UIPropertyMetadata(1)); + + #endregion + + #region MaxItemsInRow + + /// + /// Max width of the Gallery + /// + public int MaxItemsInRow + { + get { return (int)this.GetValue(MaxItemsInRowProperty); } + set { this.SetValue(MaxItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxItemsInRowProperty = + DependencyProperty.Register("MaxItemsInRow", typeof(int), + typeof(Gallery), new UIPropertyMetadata(int.MaxValue)); + + #endregion + + #region GroupBy + + /// + /// Gets or sets name of property which + /// will use to group items in the Gallery. + /// + public string GroupBy + { + get { return (string)this.GetValue(GroupByProperty); } + set { this.SetValue(GroupByProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupBy. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupByProperty = + DependencyProperty.Register("GroupBy", typeof(string), typeof(Gallery), + new UIPropertyMetadata(null)); + + #endregion + + #region Orientation + + /// + /// Gets or sets orientation of gallery + /// + public Orientation Orientation + { + get { return (Orientation)this.GetValue(OrientationProperty); } + set { this.SetValue(OrientationProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Orientation. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register("Orientation", typeof(Orientation), + typeof(Gallery), new UIPropertyMetadata(Orientation.Horizontal)); + + #endregion + + #region ItemWidth + + /// + /// Gets or sets item width + /// + public double ItemWidth + { + get { return (double)this.GetValue(ItemWidthProperty); } + set { this.SetValue(ItemWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemWidthProperty = + DependencyProperty.Register("ItemWidth", typeof(double), typeof(Gallery), new UIPropertyMetadata(double.NaN)); + + /// + /// Gets or sets item height + /// + public double ItemHeight + { + get { return (double)this.GetValue(ItemHeightProperty); } + set { this.SetValue(ItemHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), typeof(Gallery), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region Filters + + /// + /// Gets collection of filters + /// + public ObservableCollection Filters + { + get + { + if (this.filters == null) + { + this.filters = new ObservableCollection(); + this.filters.CollectionChanged += this.OnFilterCollectionChanged; + } + return this.filters; + } + } + + // Handle toolbar items changes + void OnFilterCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.HasFilter = this.Filters.Count > 0; + this.InvalidateProperty(SelectedFilterProperty); + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (int i = 0; i < e.NewItems.Count; i++) + { + if (this.groupsMenuButton != null) + { + GalleryGroupFilter filter = (GalleryGroupFilter)e.NewItems[i]; + MenuItem menuItem = new MenuItem(); + menuItem.Header = filter.Title; + menuItem.Tag = filter; + if (filter == this.SelectedFilter) menuItem.IsChecked = true; + menuItem.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Insert(e.NewStartingIndex + i, menuItem); + } + } + break; + case NotifyCollectionChangedAction.Remove: + foreach (object item in e.OldItems) + { + if (this.groupsMenuButton != null) + { + this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item as GalleryGroupFilter)); + } + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (object item in e.OldItems) + { + if (this.groupsMenuButton != null) + { + this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item as GalleryGroupFilter)); + } + } + foreach (var item in e.NewItems.OfType()) + { + if (this.groupsMenuButton != null) + { + GalleryGroupFilter filter = item; + MenuItem menuItem = new MenuItem(); + menuItem.Header = filter.Title; + menuItem.Tag = filter; + if (filter == this.SelectedFilter) menuItem.IsChecked = true; + menuItem.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Add(menuItem); + } + } + break; + } + } + + /// + /// Gets or sets selected filter + /// + public GalleryGroupFilter SelectedFilter + { + get { return (GalleryGroupFilter)this.GetValue(SelectedFilterProperty); } + set { this.SetValue(SelectedFilterProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectedFilter. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterProperty = + DependencyProperty.Register("SelectedFilter", typeof(GalleryGroupFilter), + typeof(Gallery), new UIPropertyMetadata(null, OnFilterChanged, CoerceSelectedFilter)); + + // Coerce selected filter + static object CoerceSelectedFilter(DependencyObject d, object basevalue) + { + Gallery gallery = (Gallery)d; + if ((basevalue == null) && (gallery.Filters.Count > 0)) return gallery.Filters[0]; + return basevalue; + } + + // Handles filter property changed + static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + Gallery gallery = (Gallery)d; + GalleryGroupFilter filter = e.NewValue as GalleryGroupFilter; + if (filter != null) + { + gallery.SelectedFilterTitle = filter.Title; + gallery.SelectedFilterGroups = filter.Groups; + } + else + { + gallery.SelectedFilterTitle = ""; + gallery.SelectedFilterGroups = null; + } + gallery.UpdateLayout(); + } + + /// + /// Gets selected filter title + /// + public string SelectedFilterTitle + { + get { return (string)this.GetValue(SelectedFilterTitleProperty); } + private set { this.SetValue(SelectedFilterTitlePropertyKey, value); } + } + + private static readonly DependencyPropertyKey SelectedFilterTitlePropertyKey = + DependencyProperty.RegisterReadOnly("SelectedFilterTitle", typeof(string), + typeof(Gallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for SelectedFilterTitle. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterTitleProperty = SelectedFilterTitlePropertyKey.DependencyProperty; + + /// + /// Gets selected filter groups + /// + public string SelectedFilterGroups + { + get { return (string)this.GetValue(SelectedFilterGroupsProperty); } + private set { this.SetValue(SelectedFilterGroupsPropertyKey, value); } + } + + private static readonly DependencyPropertyKey SelectedFilterGroupsPropertyKey = + DependencyProperty.RegisterReadOnly("SelectedFilterGroups", typeof(string), + typeof(Gallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for SelectedFilterGroups. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterGroupsProperty = SelectedFilterGroupsPropertyKey.DependencyProperty; + + /// + /// Gets whether gallery has selected filter + /// + public bool HasFilter + { + get { return (bool)this.GetValue(HasFilterProperty); } + private set { this.SetValue(HasFilterPropertyKey, value); } + } + + private static readonly DependencyPropertyKey HasFilterPropertyKey = DependencyProperty.RegisterReadOnly("HasFilter", typeof(bool), typeof(Gallery), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for HasFilter. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasFilterProperty = HasFilterPropertyKey.DependencyProperty; + + void OnFilterMenuItemClick(object sender, RoutedEventArgs e) + { + MenuItem senderItem = (MenuItem)sender; + MenuItem item = this.GetFilterMenuItem(this.SelectedFilter); + item.IsChecked = false; + senderItem.IsChecked = true; + this.SelectedFilter = senderItem.Tag as GalleryGroupFilter; + this.groupsMenuButton.IsDropDownOpen = false; + e.Handled = true; + } + + MenuItem GetFilterMenuItem(GalleryGroupFilter filter) + { + if (filter == null) return null; + return this.groupsMenuButton.Items.Cast().FirstOrDefault(item => (item != null) && (item.Header.ToString() == filter.Title)); + /*foreach (MenuItem item in groupsMenuButton.Items) + { + if ((item!=null)&&(item.Header == filter.Title)) return item; + } + return null;*/ + } + + #endregion + + #region Selectable + + /// + /// Gets or sets whether gallery items can be selected + /// + public bool Selectable + { + get { return (bool)this.GetValue(SelectableProperty); } + set { this.SetValue(SelectableProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Selectable. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectableProperty = + DependencyProperty.Register("Selectable", typeof(bool), + typeof(Gallery), new UIPropertyMetadata(true, OnSelectableChanged)); + + private static void OnSelectableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.CoerceValue(SelectedItemProperty); + } + + #endregion + + #region IsLastItem + + /// + /// Gets whether gallery is last item in ItemsControl + /// + public bool IsLastItem + { + get { return (bool)this.GetValue(IsLastItemProperty); } + private set { this.SetValue(IsLastItemPropertyKey, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsLastItem. This enables animation, styling, binding, etc... + /// + public static readonly DependencyPropertyKey IsLastItemPropertyKey = DependencyProperty.RegisterReadOnly("IsLastItem", typeof(bool), typeof(Gallery), new UIPropertyMetadata(false)); + /// + /// Using a DependencyProperty as the backing store for IsLastItem. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsLastItemProperty = IsLastItemPropertyKey.DependencyProperty; + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static Gallery() + { + Type type = typeof(Gallery); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(typeof(Gallery))); + SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, CoerceSelectedItem)); + ContextMenuService.Attach(type); + StyleProperty.OverrideMetadata(typeof(Gallery), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(Gallery)); + } + + return basevalue; + } + + // Coerce selected item + private static object CoerceSelectedItem(DependencyObject d, object basevalue) + { + Gallery gallery = (Gallery)d; + + if (!gallery.Selectable) + { + GalleryItem galleryItem = (GalleryItem)gallery.ItemContainerGenerator.ContainerFromItem(basevalue); + + if (basevalue != null && galleryItem != null) + { + galleryItem.IsSelected = false; + } + + return null; + } + + return basevalue; + } + + /// + /// Default constructor + /// + public Gallery() + { + ContextMenuService.Coerce(this); + this.Loaded += this.OnLoaded; + this.Focusable = false; + KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Continue); + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + ItemsControl parent = this.Parent as ItemsControl; + if (parent != null) + { + if (parent.Items.IndexOf(this) == parent.Items.Count - 1) + { + this.IsLastItem = true; + } + else + { + this.IsLastItem = false; + } + } + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new GalleryItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is GalleryItem; + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + if (this.groupsMenuButton != null) + { + this.groupsMenuButton.Items.Clear(); + } + + this.groupsMenuButton = this.GetTemplateChild("PART_DropDownButton") as DropDownButton; + + if (this.groupsMenuButton != null) + { + for (int i = 0; i < this.Filters.Count; i++) + { + var item = new MenuItem + { + Header = this.Filters[i].Title, + Tag = this.Filters[i], + IsDefinitive = false + }; + + if (this.Filters[i] == this.SelectedFilter) + { + item.IsChecked = true; + } + + item.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Add(item); + } + } + + base.OnApplyTemplate(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/GalleryGroupContainer.cs b/Fluent.Ribbon/Controls/GalleryGroupContainer.cs similarity index 77% rename from Fluent/Controls/GalleryGroupContainer.cs rename to Fluent.Ribbon/Controls/GalleryGroupContainer.cs index 67a5ed4cc..b67428d03 100644 --- a/Fluent/Controls/GalleryGroupContainer.cs +++ b/Fluent.Ribbon/Controls/GalleryGroupContainer.cs @@ -1,306 +1,334 @@ -using System; -using System.Diagnostics; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Threading; - -namespace Fluent -{ - /// - /// Represents container of grouped gallery items in GalleryPanel or Gallery - /// - public class GalleryGroupContainer : HeaderedItemsControl - { - #region Fields - - private Panel previousItemsPanel; - private int previousItemsCount; - - // Whether MaxWidth of the ItemsPanel needs to be updated - private bool maxMinWidthNeedsToBeUpdated; - - #endregion - - #region Properites - - #region IsHeadered - - /// - /// Gets or sets whether the header must be shown. - /// When the property is false this control uses to show all items without grouping - /// - public bool IsHeadered - { - get { return (bool)this.GetValue(IsHeaderedProperty); } - set { this.SetValue(IsHeaderedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsHeadered. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsHeaderedProperty = - DependencyProperty.Register("IsHeadered", typeof(bool), - typeof(GalleryGroupContainer), new UIPropertyMetadata(true)); - - #endregion - - #region Orientation - - /// - /// Gets or sets panel orientation - /// - public Orientation Orientation - { - get { return (Orientation)this.GetValue(OrientationProperty); } - set { this.SetValue(OrientationProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Orientation. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty OrientationProperty = - DependencyProperty.Register("Orientation", typeof(Orientation), - typeof(GalleryGroupContainer), new UIPropertyMetadata(Orientation.Horizontal)); - - #endregion - - #region ItemWidth - - /// - /// Gets or sets a value that specifies the width of - /// all items that are contained within - /// - public double ItemWidth - { - get { return (double)this.GetValue(ItemWidthProperty); } - set { this.SetValue(ItemWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemWidth. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemWidthProperty = - DependencyProperty.Register("ItemWidth", typeof(double), - typeof(GalleryGroupContainer), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ItemHeight - - /// - /// Gets or sets a value that specifies the height of - /// all items that are contained within - /// - public double ItemHeight - { - get { return (double)this.GetValue(ItemHeightProperty); } - set { this.SetValue(ItemHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemHeight. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), - typeof(GalleryGroupContainer), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region MinItemsInRow - - /// - /// Gets or sets minimum items quantity in row - /// - public int MinItemsInRow - { - get { return (int)this.GetValue(MinItemsInRowProperty); } - set { this.SetValue(MinItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinItemsInRowProperty = - DependencyProperty.Register("MinItemsInRow", typeof(int), - typeof(GalleryGroupContainer), new UIPropertyMetadata(0, OnMaxMinItemsInRowChanged)); - - static void OnMaxMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - GalleryGroupContainer galleryGroupContainer = (GalleryGroupContainer) d; - galleryGroupContainer.maxMinWidthNeedsToBeUpdated = true; - } - - #endregion - - #region MaxItemsInRow - - /// - /// Gets or sets maximum items quantity in row - /// - public int MaxItemsInRow - { - get { return (int)this.GetValue(MaxItemsInRowProperty); } - set { this.SetValue(MaxItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxItemsInRowProperty = - DependencyProperty.Register("MaxItemsInRow", typeof(int), - typeof(GalleryGroupContainer), new UIPropertyMetadata(int.MaxValue, OnMaxMinItemsInRowChanged)); - - #endregion - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - static GalleryGroupContainer() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(GalleryGroupContainer), new FrameworkPropertyMetadata(typeof(GalleryGroupContainer))); - StyleProperty.OverrideMetadata(typeof(GalleryGroupContainer), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = ((FrameworkElement)d).TryFindResource(typeof(GalleryGroupContainer)); - } - - return basevalue; - } - - #endregion - - #region MaxWidth Updating - - // Sets MaxWidth of the items panel based of ItemsInRow property - private void UpdateMinAndMaxWidth() - { - this.maxMinWidthNeedsToBeUpdated = false; - - var itemsPanel = FindItemsPanel(this); - if (itemsPanel == null) - { - // Item's panel is not ready now - if (this.IsLoaded) - { - Debug.WriteLine("Panel with IsItemsHost = true is not found in GalleryGroupContainer (probably the style is not correct or haven't attached yet)"); - } - - this.Dispatcher.BeginInvoke((Action)this.InvalidateMeasure, DispatcherPriority.ContextIdle); - return; - } - - if (this.Orientation == Orientation.Vertical) - { - // Min/Max is used for Horizontal layout only - itemsPanel.MinWidth = 0; - itemsPanel.MaxWidth = double.PositiveInfinity; - return; - } - - var itemWidth = this.GetItemWidth(); - if (double.IsNaN(itemWidth)) - { - // We can't calc item's width now - return; - } - - itemsPanel.MinWidth = Math.Min(this.Items.Count, this.MinItemsInRow) * itemWidth + 0.1; - itemsPanel.MaxWidth = Math.Min(this.Items.Count, this.MaxItemsInRow) * itemWidth + 0.1; - } - - /// - /// Determinates item's size (return Size.Empty in case of it is not possible) - /// - /// - public Size GetItemSize() - { - if (!double.IsNaN(this.ItemWidth) - && !double.IsNaN(this.ItemHeight)) - { - return new Size(this.ItemWidth, this.ItemHeight); - } - - if (this.Items.Count == 0) - { - return Size.Empty; - } - - var anItem = this.ItemContainerGenerator.ContainerFromItem(this.Items[0]) as UIElement; - if (anItem == null) - { - return Size.Empty; - } - - anItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - var result = anItem.DesiredSize; - anItem.InvalidateMeasure(); - return result; - } - - // Determinates item's width (return Double.NaN in case of it is not possible) - private double GetItemWidth() - { - return this.GetItemSize().Width; - } - - // Finds panel with IsItemsHost, or null if such panel is not found - private static Panel FindItemsPanel(DependencyObject obj) - { - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) - { - var panel = obj as Panel; - if (panel != null && - panel.IsItemsHost) - { - return panel; - } - - panel = FindItemsPanel(VisualTreeHelper.GetChild(obj, i)); - if (panel != null) - { - return panel; - } - } - - return null; - } - - #endregion - - /// - /// Called to remeasure a control. - /// - /// The size of the control, up to the maximum specified by constraint. - /// The maximum size that the method can return. - protected override Size MeasureOverride(Size constraint) - { - var panel = FindItemsPanel(this); - if (panel != this.previousItemsPanel - || this.previousItemsCount != this.Items.Count - || this.maxMinWidthNeedsToBeUpdated) - { - // Track ItemsPanel changing - this.previousItemsPanel = panel; - this.previousItemsCount = this.Items.Count; - this.UpdateMinAndMaxWidth(); - } - return base.MeasureOverride(constraint); - } - } +using System; +using System.Diagnostics; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Threading; + +namespace Fluent +{ + /// + /// Represents container of grouped gallery items in GalleryPanel or Gallery + /// + public class GalleryGroupContainer : HeaderedItemsControl + { + #region Fields + + private int previousItemsCount; + + // Whether MinWidth/MaxWidth of the ItemsPanel needs to be updated + private bool minMaxWidthNeedsToBeUpdated = true; + private Panel itemsPanel; + + #endregion + + #region Properites + + #region IsHeadered + + /// + /// Gets or sets whether the header must be shown. + /// When the property is false this control uses to show all items without grouping + /// + public bool IsHeadered + { + get { return (bool)this.GetValue(IsHeaderedProperty); } + set { this.SetValue(IsHeaderedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsHeadered. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsHeaderedProperty = + DependencyProperty.Register("IsHeadered", typeof(bool), + typeof(GalleryGroupContainer), new UIPropertyMetadata(true)); + + #endregion + + #region Orientation + + /// + /// Gets or sets panel orientation + /// + public Orientation Orientation + { + get { return (Orientation)this.GetValue(OrientationProperty); } + set { this.SetValue(OrientationProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Orientation. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register("Orientation", typeof(Orientation), + typeof(GalleryGroupContainer), new UIPropertyMetadata(Orientation.Horizontal)); + + #endregion + + #region ItemWidth + + /// + /// Gets or sets a value that specifies the width of + /// all items that are contained within + /// + public double ItemWidth + { + get { return (double)this.GetValue(ItemWidthProperty); } + set { this.SetValue(ItemWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemWidth. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemWidthProperty = + DependencyProperty.Register("ItemWidth", typeof(double), + typeof(GalleryGroupContainer), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ItemHeight + + /// + /// Gets or sets a value that specifies the height of + /// all items that are contained within + /// + public double ItemHeight + { + get { return (double)this.GetValue(ItemHeightProperty); } + set { this.SetValue(ItemHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemHeight. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), + typeof(GalleryGroupContainer), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region MinItemsInRow + + /// + /// Gets or sets minimum items quantity in row + /// + public int MinItemsInRow + { + get { return (int)this.GetValue(MinItemsInRowProperty); } + set { this.SetValue(MinItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinItemsInRowProperty = + DependencyProperty.Register("MinItemsInRow", typeof(int), + typeof(GalleryGroupContainer), new UIPropertyMetadata(0, OnMaxMinItemsInRowChanged)); + + #endregion + + #region MaxItemsInRow + + /// + /// Gets or sets maximum items quantity in row + /// + public int MaxItemsInRow + { + get { return (int)this.GetValue(MaxItemsInRowProperty); } + set { this.SetValue(MaxItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxItemsInRowProperty = + DependencyProperty.Register("MaxItemsInRow", typeof(int), + typeof(GalleryGroupContainer), new UIPropertyMetadata(int.MaxValue, OnMaxMinItemsInRowChanged)); + + #endregion + + private Panel RealItemsPanel + { + get + { + return this.itemsPanel ?? (this.itemsPanel = FindItemsPanel(this)); + } + } + + private static void OnMaxMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var galleryGroupContainer = (GalleryGroupContainer)d; + galleryGroupContainer.minMaxWidthNeedsToBeUpdated = true; + } + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + static GalleryGroupContainer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(GalleryGroupContainer), new FrameworkPropertyMetadata(typeof(GalleryGroupContainer))); + } + + /// + /// Invoked when the property changes. + /// + /// Old value of the property.New value of the property. + protected override void OnItemsPanelChanged(ItemsPanelTemplate oldItemsPanel, ItemsPanelTemplate newItemsPanel) + { + base.OnItemsPanelChanged(oldItemsPanel, newItemsPanel); + + this.itemsPanel = null; + this.minMaxWidthNeedsToBeUpdated = true; + this.InvalidateMeasure(); + } + + #endregion + + #region MaxWidth Updating + + // Sets MaxWidth of the items panel based of ItemsInRow property + private void UpdateMinAndMaxWidth() + { + if (this.minMaxWidthNeedsToBeUpdated == false) + { + return; + } + + if (this.RealItemsPanel == null) + { + // Item's panel is not ready now + if (this.IsLoaded) + { + Debug.WriteLine("Panel with IsItemsHost = true is not found in GalleryGroupContainer (probably the style is not correct or haven't attached yet)"); + } + else + { + // Prevent duplicate registration + this.Loaded -= this.HandleLoaded; + this.Loaded += this.HandleLoaded; + } + + return; + } + + this.minMaxWidthNeedsToBeUpdated = false; + + if (this.Orientation == Orientation.Vertical) + { + // Min/Max is used for Horizontal layout only + this.RealItemsPanel.MinWidth = 0; + this.RealItemsPanel.MaxWidth = double.PositiveInfinity; + return; + } + + var itemWidth = this.GetItemWidth(); + if (double.IsNaN(itemWidth)) + { + // We can't calc item's width now + return; + } + + this.RealItemsPanel.MinWidth = Math.Min(this.Items.Count, this.MinItemsInRow) * itemWidth + 0.1; + this.RealItemsPanel.MaxWidth = Math.Min(this.Items.Count, this.MaxItemsInRow) * itemWidth + 0.1; + } + + private void HandleLoaded(object sender, RoutedEventArgs e) + { + this.Loaded -= this.HandleLoaded; + + if (this.minMaxWidthNeedsToBeUpdated == false) + { + return; + } + + this.InvalidateMeasure(); + } + + /// + /// Determinates item's size (return Size.Empty in case of it is not possible) + /// + /// + public Size GetItemSize() + { + if (!double.IsNaN(this.ItemWidth) + && !double.IsNaN(this.ItemHeight)) + { + return new Size(this.ItemWidth, this.ItemHeight); + } + + if (this.Items.Count == 0) + { + return Size.Empty; + } + + var anItem = this.ItemContainerGenerator.ContainerFromItem(this.Items[0]) as UIElement; + if (anItem == null) + { + return Size.Empty; + } + + anItem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + var result = anItem.DesiredSize; + anItem.InvalidateMeasure(); + return result; + } + + // Determinates item's width (return Double.NaN in case of it is not possible) + private double GetItemWidth() + { + return this.GetItemSize().Width; + } + + // Finds panel with IsItemsHost, or null if such panel is not found + private static Panel FindItemsPanel(DependencyObject obj) + { + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) + { + var panel = obj as Panel; + if (panel != null && + panel.IsItemsHost) + { + return panel; + } + + panel = FindItemsPanel(VisualTreeHelper.GetChild(obj, i)); + if (panel != null) + { + return panel; + } + } + + return null; + } + + #endregion + + /// + /// Called to remeasure a control. + /// + /// The size of the control, up to the maximum specified by constraint. + /// The maximum size that the method can return. + protected override Size MeasureOverride(Size constraint) + { + if (this.previousItemsCount != this.Items.Count + || this.minMaxWidthNeedsToBeUpdated) + { + // Track ItemsPanel changing + this.previousItemsCount = this.Items.Count; + this.UpdateMinAndMaxWidth(); + } + + return base.MeasureOverride(constraint); + } + } } \ No newline at end of file diff --git a/Fluent/Controls/GalleryGroupFilter.cs b/Fluent.Ribbon/Controls/GalleryGroupFilter.cs similarity index 72% rename from Fluent/Controls/GalleryGroupFilter.cs rename to Fluent.Ribbon/Controls/GalleryGroupFilter.cs index 86eebdd8e..b0e27fe4b 100644 --- a/Fluent/Controls/GalleryGroupFilter.cs +++ b/Fluent.Ribbon/Controls/GalleryGroupFilter.cs @@ -1,57 +1,44 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Windows; - -namespace Fluent -{ - /// - /// Represents gallery group filter definition - /// - public class GalleryGroupFilter : DependencyObject - { - #region Properties - - /// - /// Gets or sets title of filter - /// - public string Title - { - get { return (string)this.GetValue(TitleProperty); } - set { this.SetValue(TitleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Title. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), - typeof(GalleryGroupFilter), new UIPropertyMetadata("GalleryGroupFilter")); - - /// - /// Gets or sets list pf groups splitted by comma - /// - public string Groups - { - get { return (string)this.GetValue(GroupsProperty); } - set { this.SetValue(GroupsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ContextualGroups. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupsProperty = - DependencyProperty.Register("ContextualGroups", typeof(string), - typeof(GalleryGroupFilter), new UIPropertyMetadata("")); - - #endregion - } -} +using System.Windows; + +namespace Fluent +{ + /// + /// Represents gallery group filter definition + /// + public class GalleryGroupFilter : DependencyObject + { + /// + /// Gets or sets title of filter + /// + public string Title + { + get { return (string)this.GetValue(TitleProperty); } + set { this.SetValue(TitleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Title. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), + typeof(GalleryGroupFilter), new UIPropertyMetadata("GalleryGroupFilter")); + + /// + /// Gets or sets list pf groups splitted by comma + /// + public string Groups + { + get { return (string)this.GetValue(GroupsProperty); } + set { this.SetValue(GroupsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ContextualGroups. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupsProperty = + DependencyProperty.Register("ContextualGroups", typeof(string), + typeof(GalleryGroupFilter), new UIPropertyMetadata(string.Empty)); + } +} \ No newline at end of file diff --git a/Fluent/Controls/GalleryItem.cs b/Fluent.Ribbon/Controls/GalleryItem.cs similarity index 95% rename from Fluent/Controls/GalleryItem.cs rename to Fluent.Ribbon/Controls/GalleryItem.cs index 29c23124b..92c45f576 100644 --- a/Fluent/Controls/GalleryItem.cs +++ b/Fluent.Ribbon/Controls/GalleryItem.cs @@ -1,475 +1,466 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; - -namespace Fluent -{ - using Fluent.Internal; - - /// - /// Represents gallery item - /// - public class GalleryItem : ListBoxItem, IKeyTipedControl - { - #region Properties - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(GalleryItem)); - - #endregion - - /// - /// Gets a value that indicates whether a Button is currently activated. - /// This is a dependency property. - /// - public bool IsPressed - { - get { return (bool)this.GetValue(IsPressedProperty); } - private set { this.SetValue(IsPressedPropertyKey, value); } - } - - private static readonly DependencyPropertyKey IsPressedPropertyKey = - DependencyProperty.RegisterReadOnly("IsPressed", typeof(bool), - typeof(GalleryItem), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for IsPressed. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsPressedProperty = IsPressedPropertyKey.DependencyProperty; - - /// - /// Gets or sets GalleryItem group - /// - public string Group - { - get { return (string)this.GetValue(GroupProperty); } - set { this.SetValue(GroupProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Group. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupProperty = - DependencyProperty.Register("Group", typeof(string), - typeof(GalleryItem), new UIPropertyMetadata(null)); - - - #region Command - - private bool currentCanExecute = true; - - /// - /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. - /// - [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] - public ICommand Command - { - get - { - return (ICommand)this.GetValue(CommandProperty); - } - set - { - this.SetValue(CommandProperty, value); - } - } - - /// - /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. - /// - [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] - public object CommandParameter - { - get - { - return this.GetValue(CommandParameterProperty); - } - set - { - this.SetValue(CommandParameterProperty, value); - } - } - - /// - /// Gets or sets the element on which to raise the specified command. This is a dependency property. - /// - [Bindable(true), Category("Action")] - public IInputElement CommandTarget - { - get - { - return (IInputElement)this.GetValue(CommandTargetProperty); - } - set - { - this.SetValue(CommandTargetProperty, value); - } - } - - /// - /// Identifies the CommandParameter dependency property. - /// - public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(GalleryItem), new FrameworkPropertyMetadata(null)); - - /// - /// Identifies the routed Command dependency property. - /// - public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(GalleryItem), new FrameworkPropertyMetadata(null, OnCommandChanged)); - - /// - /// Identifies the CommandTarget dependency property. - /// - public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(GalleryItem), new FrameworkPropertyMetadata(null)); - - /// - /// Gets or sets the command to invoke when mouse enters or leaves this button. The commandparameter will be the instance. - /// This is a dependency property. - /// - [Bindable(true), Category("Action")] - public ICommand PreviewCommand - { - get { return (ICommand)this.GetValue(PreviewCommandProperty); } - set { this.SetValue(PreviewCommandProperty, value); } - } - - /// - /// Identifies the PreviewCommand dependency property. - /// - public static readonly DependencyProperty PreviewCommandProperty = - DependencyProperty.Register("PreviewCommand", typeof(ICommand), typeof(GalleryItem), new PropertyMetadata(null)); - - /// - /// Gets or sets the command to invoke when mouse enters or leaves this button. The commandparameter will be the instance. - /// This is a dependency property. - /// - [Bindable(true), Category("Action")] - public ICommand CancelPreviewCommand - { - get { return (ICommand)this.GetValue(CancelPreviewCommandProperty); } - set { this.SetValue(CancelPreviewCommandProperty, value); } - } - - /// - /// Identifies the PreviewCommand dependency property. - /// - public static readonly DependencyProperty CancelPreviewCommandProperty = - DependencyProperty.Register("CancelPreviewCommand", typeof(ICommand), typeof(GalleryItem), new PropertyMetadata(null)); - - /// - /// Handles Command changed - /// - /// - /// - private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = d as GalleryItem; - if (control == null) - { - return; - } - - var oldCommand = e.OldValue as ICommand; - if (oldCommand != null) - { - oldCommand.CanExecuteChanged -= control.OnCommandCanExecuteChanged; - } - - var newCommand = e.NewValue as ICommand; - if (newCommand != null) - { - newCommand.CanExecuteChanged += control.OnCommandCanExecuteChanged; - } - - control.UpdateCanExecute(); - } - /// - /// Handles Command CanExecute changed - /// - /// - /// - private void OnCommandCanExecuteChanged(object sender, EventArgs e) - { - this.UpdateCanExecute(); - } - - private void UpdateCanExecute() - { - var canExecute = this.Command != null - && this.CanExecuteCommand(); - if (this.currentCanExecute != canExecute) - { - this.currentCanExecute = canExecute; - this.CoerceValue(IsEnabledProperty); - } - } - - /// - /// Execute command - /// - protected void ExecuteCommand() - { - CommandHelper.Execute(this.Command, this.CommandParameter, this.CommandTarget); - } - - /// - /// Determines whether the Command can be executed - /// - /// Returns Command CanExecute - protected bool CanExecuteCommand() - { - return CommandHelper.CanExecute(this.Command, this.CommandParameter, this.CommandTarget); - } - - #endregion - - #region IsEnabled - - /// - /// Gets a value that becomes the return - /// value of IsEnabled in derived classes. - /// - /// - /// true if the element is enabled; otherwise, false. - /// - protected override bool IsEnabledCore - { - get - { - return (base.IsEnabledCore && (this.currentCanExecute || this.Command == null)); - } - } - - #endregion - - #endregion - - #region Events - - #region Click - - /// - /// Occurs when a RibbonControl is clicked. - /// - [Category("Behavior")] - public event RoutedEventHandler Click - { - add - { - this.AddHandler(ClickEvent, value); - } - remove - { - this.RemoveHandler(ClickEvent, value); - } - } - - /// - /// Identifies the RibbonControl.Click routed event. - /// - public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(GalleryItem)); - - /// - /// Raises click event - /// - [SuppressMessage("Microsoft.Design", "CA1030")] - public void RaiseClick() - { - this.RaiseEvent(new RoutedEventArgs(ClickEvent, this)); - } - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static GalleryItem() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(GalleryItem), new FrameworkPropertyMetadata(typeof(GalleryItem))); - IsSelectedProperty.AddOwner(typeof(GalleryItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, OnIsSelectedPropertyChanged)); - StyleProperty.OverrideMetadata(typeof(GalleryItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(GalleryItem)); - } - - return basevalue; - } - - static void OnIsSelectedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if ((bool)e.NewValue) - { - ((GalleryItem)d).BringIntoView(); - - var parentSelector = ItemsControl.ItemsControlFromItemContainer(d) as Selector; - - if (parentSelector != null) - { - var item = parentSelector.ItemContainerGenerator.ItemFromContainer(d); - - if (ReferenceEquals(parentSelector.SelectedItem, item) == false) - { - parentSelector.SelectedItem = item; - } - } - } - } - - /// - /// Default constructor - /// - public GalleryItem() - { - this.Click += this.OnClick; - } - - #endregion - - #region Overrides - - /// - /// Provides class handling for the System.Windows.UIElement.MouseLeftButtonDown routed event that occurs - /// when the left mouse button is pressed while the mouse pointer is over this control. - /// - /// The event data. - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - this.IsPressed = true; - Mouse.Capture(this); - e.Handled = true; - } - - /// - /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The that contains event data. - protected override void OnLostMouseCapture(MouseEventArgs e) - { - base.OnLostMouseCapture(e); - - this.IsPressed = false; - } - - /// - /// Provides class handling for the System.Windows.UIElement.MouseLeftButtonUp routed event that occurs - /// when the left mouse button is released while the mouse pointer is over this control. - /// - /// The event data. - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) - { - this.IsPressed = false; - if (Mouse.Captured == this) - { - Mouse.Capture(null); - } - - var position = Mouse.PrimaryDevice.GetPosition(this); - - if ((position.X >= 0.0 && position.X <= this.ActualWidth) - && (position.Y >= 0.0 && position.Y <= this.ActualHeight) - && e.ClickCount == 1) - { - this.RaiseClick(); - e.Handled = true; - } - - e.Handled = true; - } - - /// - /// Called when the mouse enters a . - /// - /// The event data. - protected override void OnMouseEnter(MouseEventArgs e) - { - base.OnMouseEnter(e); - - CommandHelper.Execute(this.PreviewCommand, this, null); - } - - /// - /// Called when the mouse leaves a . - /// - /// The event data. - protected override void OnMouseLeave(MouseEventArgs e) - { - base.OnMouseLeave(e); - - CommandHelper.Execute(this.CancelPreviewCommand, this, null); - } - - #endregion - - #region Protected methods - - /// - /// Handles click event - /// - /// Sender - /// The event data - protected virtual void OnClick(object sender, RoutedEventArgs e) - { - PopupService.RaiseDismissPopupEvent(sender, DismissPopupMode.Always); - - this.ExecuteCommand(); - this.IsSelected = true; - e.Handled = true; - } - - #endregion - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.RaiseClick(); - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - } +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; + +namespace Fluent +{ + using Fluent.Internal; + + /// + /// Represents gallery item + /// + public class GalleryItem : ListBoxItem, IKeyTipedControl + { + #region Properties + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(GalleryItem)); + + #endregion + + /// + /// Gets a value that indicates whether a Button is currently activated. + /// This is a dependency property. + /// + public bool IsPressed + { + get { return (bool)this.GetValue(IsPressedProperty); } + private set { this.SetValue(IsPressedPropertyKey, value); } + } + + private static readonly DependencyPropertyKey IsPressedPropertyKey = + DependencyProperty.RegisterReadOnly("IsPressed", typeof(bool), + typeof(GalleryItem), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for IsPressed. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsPressedProperty = IsPressedPropertyKey.DependencyProperty; + + /// + /// Gets or sets GalleryItem group + /// + public string Group + { + get { return (string)this.GetValue(GroupProperty); } + set { this.SetValue(GroupProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Group. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupProperty = + DependencyProperty.Register("Group", typeof(string), + typeof(GalleryItem), new UIPropertyMetadata(null)); + + + #region Command + + private bool currentCanExecute = true; + + /// + /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. + /// + [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] + public ICommand Command + { + get + { + return (ICommand)this.GetValue(CommandProperty); + } + set + { + this.SetValue(CommandProperty, value); + } + } + + /// + /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. + /// + [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] + public object CommandParameter + { + get + { + return this.GetValue(CommandParameterProperty); + } + set + { + this.SetValue(CommandParameterProperty, value); + } + } + + /// + /// Gets or sets the element on which to raise the specified command. This is a dependency property. + /// + [Bindable(true), Category("Action")] + public IInputElement CommandTarget + { + get + { + return (IInputElement)this.GetValue(CommandTargetProperty); + } + set + { + this.SetValue(CommandTargetProperty, value); + } + } + + /// + /// Identifies the CommandParameter dependency property. + /// + public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(GalleryItem), new FrameworkPropertyMetadata(null)); + + /// + /// Identifies the routed Command dependency property. + /// + public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(GalleryItem), new FrameworkPropertyMetadata(null, OnCommandChanged)); + + /// + /// Identifies the CommandTarget dependency property. + /// + public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(GalleryItem), new FrameworkPropertyMetadata(null)); + + /// + /// Gets or sets the command to invoke when mouse enters or leaves this button. The commandparameter will be the instance. + /// This is a dependency property. + /// + [Bindable(true), Category("Action")] + public ICommand PreviewCommand + { + get { return (ICommand)this.GetValue(PreviewCommandProperty); } + set { this.SetValue(PreviewCommandProperty, value); } + } + + /// + /// Identifies the PreviewCommand dependency property. + /// + public static readonly DependencyProperty PreviewCommandProperty = + DependencyProperty.Register("PreviewCommand", typeof(ICommand), typeof(GalleryItem), new PropertyMetadata(null)); + + /// + /// Gets or sets the command to invoke when mouse enters or leaves this button. The commandparameter will be the instance. + /// This is a dependency property. + /// + [Bindable(true), Category("Action")] + public ICommand CancelPreviewCommand + { + get { return (ICommand)this.GetValue(CancelPreviewCommandProperty); } + set { this.SetValue(CancelPreviewCommandProperty, value); } + } + + /// + /// Identifies the PreviewCommand dependency property. + /// + public static readonly DependencyProperty CancelPreviewCommandProperty = + DependencyProperty.Register("CancelPreviewCommand", typeof(ICommand), typeof(GalleryItem), new PropertyMetadata(null)); + + /// + /// Handles Command changed + /// + /// + /// + private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = d as GalleryItem; + if (control == null) + { + return; + } + + var oldCommand = e.OldValue as ICommand; + if (oldCommand != null) + { + oldCommand.CanExecuteChanged -= control.OnCommandCanExecuteChanged; + } + + var newCommand = e.NewValue as ICommand; + if (newCommand != null) + { + newCommand.CanExecuteChanged += control.OnCommandCanExecuteChanged; + } + + control.UpdateCanExecute(); + } + /// + /// Handles Command CanExecute changed + /// + /// + /// + private void OnCommandCanExecuteChanged(object sender, EventArgs e) + { + this.UpdateCanExecute(); + } + + private void UpdateCanExecute() + { + var canExecute = this.Command != null + && this.CanExecuteCommand(); + if (this.currentCanExecute != canExecute) + { + this.currentCanExecute = canExecute; + this.CoerceValue(IsEnabledProperty); + } + } + + /// + /// Execute command + /// + protected void ExecuteCommand() + { + CommandHelper.Execute(this.Command, this.CommandParameter, this.CommandTarget); + } + + /// + /// Determines whether the Command can be executed + /// + /// Returns Command CanExecute + protected bool CanExecuteCommand() + { + return CommandHelper.CanExecute(this.Command, this.CommandParameter, this.CommandTarget); + } + + #endregion + + #region IsEnabled + + /// + /// Gets a value that becomes the return + /// value of IsEnabled in derived classes. + /// + /// + /// true if the element is enabled; otherwise, false. + /// + protected override bool IsEnabledCore + { + get + { + return (base.IsEnabledCore && (this.currentCanExecute || this.Command == null)); + } + } + + #endregion + + #endregion + + #region Events + + #region Click + + /// + /// Occurs when a RibbonControl is clicked. + /// + [Category("Behavior")] + public event RoutedEventHandler Click + { + add + { + this.AddHandler(ClickEvent, value); + } + remove + { + this.RemoveHandler(ClickEvent, value); + } + } + + /// + /// Identifies the RibbonControl.Click routed event. + /// + public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(GalleryItem)); + + /// + /// Raises click event + /// + [SuppressMessage("Microsoft.Design", "CA1030")] + public void RaiseClick() + { + this.RaiseEvent(new RoutedEventArgs(ClickEvent, this)); + } + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static GalleryItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(GalleryItem), new FrameworkPropertyMetadata(typeof(GalleryItem))); + IsSelectedProperty.AddOwner(typeof(GalleryItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.None, OnIsSelectedPropertyChanged)); + StyleProperty.OverrideMetadata(typeof(GalleryItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(GalleryItem)); + } + + return basevalue; + } + + static void OnIsSelectedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) + { + ((GalleryItem)d).BringIntoView(); + + var parentSelector = ItemsControl.ItemsControlFromItemContainer(d) as Selector; + + if (parentSelector != null) + { + var item = parentSelector.ItemContainerGenerator.ItemFromContainer(d); + + if (ReferenceEquals(parentSelector.SelectedItem, item) == false) + { + parentSelector.SelectedItem = item; + } + } + } + } + + /// + /// Default constructor + /// + public GalleryItem() + { + this.Click += this.OnClick; + } + + #endregion + + #region Overrides + + /// + /// Provides class handling for the System.Windows.UIElement.MouseLeftButtonDown routed event that occurs + /// when the left mouse button is pressed while the mouse pointer is over this control. + /// + /// The event data. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + this.IsPressed = true; + Mouse.Capture(this); + e.Handled = true; + } + + /// + /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains event data. + protected override void OnLostMouseCapture(MouseEventArgs e) + { + base.OnLostMouseCapture(e); + + this.IsPressed = false; + } + + /// + /// Provides class handling for the System.Windows.UIElement.MouseLeftButtonUp routed event that occurs + /// when the left mouse button is released while the mouse pointer is over this control. + /// + /// The event data. + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + this.IsPressed = false; + if (Mouse.Captured == this) + { + Mouse.Capture(null); + } + + var position = Mouse.PrimaryDevice.GetPosition(this); + + if ((position.X >= 0.0 && position.X <= this.ActualWidth) + && (position.Y >= 0.0 && position.Y <= this.ActualHeight) + && e.ClickCount == 1) + { + this.RaiseClick(); + e.Handled = true; + } + + e.Handled = true; + } + + /// + /// Called when the mouse enters a . + /// + /// The event data. + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + + CommandHelper.Execute(this.PreviewCommand, this, null); + } + + /// + /// Called when the mouse leaves a . + /// + /// The event data. + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseLeave(e); + + CommandHelper.Execute(this.CancelPreviewCommand, this, null); + } + + #endregion + + #region Protected methods + + /// + /// Handles click event + /// + /// Sender + /// The event data + protected virtual void OnClick(object sender, RoutedEventArgs e) + { + PopupService.RaiseDismissPopupEvent(sender, DismissPopupMode.Always); + + this.ExecuteCommand(); + this.IsSelected = true; + e.Handled = true; + } + + #endregion + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.RaiseClick(); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + } } \ No newline at end of file diff --git a/Fluent/Controls/GalleryItemPlaceholder.cs b/Fluent.Ribbon/Controls/GalleryItemPlaceholder.cs similarity index 96% rename from Fluent/Controls/GalleryItemPlaceholder.cs rename to Fluent.Ribbon/Controls/GalleryItemPlaceholder.cs index 4a5ccf858..ae2a0e74e 100644 --- a/Fluent/Controls/GalleryItemPlaceholder.cs +++ b/Fluent.Ribbon/Controls/GalleryItemPlaceholder.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents internal class to use it in - /// GalleryPanel as placeholder for GalleryItems - /// - class GalleryItemPlaceholder : UIElement - { - #region Fields - - UIElement target; - - #endregion - - #region Properties - - /// - /// Gets the target of the placeholder - /// - public UIElement Target - { - get { return this.target; } - } - - public Size ArrangedSize { get; private set; } - - #endregion - - #region Initialization - - /// - /// Constructor - /// - /// Target - public GalleryItemPlaceholder(UIElement target) - { - this.target = target; - } - - #endregion - - #region Methods - - /// - /// When overridden in a derived class, measures the size in layout - /// required for child elements and determines a size for the derived class. - /// - /// - /// The size that this element determines it needs during layout, - /// based on its calculations of child element sizes. - /// - /// The available size that this element can - /// give to child elements. Infinity can be specified as a value to - /// indicate that the element will size to whatever content is available. - protected override Size MeasureCore(Size availableSize) - { - this.target.Measure(availableSize); - return this.target.DesiredSize; - } - - /// - /// Defines the template for WPF core-level arrange layout definition. - /// - /// - /// The final area within the parent that element should use to - /// arrange itself and its child elements. - protected override void ArrangeCore(Rect finalRect) - { - base.ArrangeCore(finalRect); - - // Remember arranged size to arrange - // targets in GalleryPanel lately - this.ArrangedSize = finalRect.Size; - } - - #endregion - - #region Debug - - /* FOR DEGUG - protected override void OnRender(DrawingContext drawingContext) - { - drawingContext.DrawRectangle(null, new Pen(Brushes.Red, 1), new Rect(RenderSize)); - }*/ - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents internal class to use it in + /// GalleryPanel as placeholder for GalleryItems + /// + class GalleryItemPlaceholder : UIElement + { + #region Fields + + UIElement target; + + #endregion + + #region Properties + + /// + /// Gets the target of the placeholder + /// + public UIElement Target + { + get { return this.target; } + } + + public Size ArrangedSize { get; private set; } + + #endregion + + #region Initialization + + /// + /// Constructor + /// + /// Target + public GalleryItemPlaceholder(UIElement target) + { + this.target = target; + } + + #endregion + + #region Methods + + /// + /// When overridden in a derived class, measures the size in layout + /// required for child elements and determines a size for the derived class. + /// + /// + /// The size that this element determines it needs during layout, + /// based on its calculations of child element sizes. + /// + /// The available size that this element can + /// give to child elements. Infinity can be specified as a value to + /// indicate that the element will size to whatever content is available. + protected override Size MeasureCore(Size availableSize) + { + this.target.Measure(availableSize); + return this.target.DesiredSize; + } + + /// + /// Defines the template for WPF core-level arrange layout definition. + /// + /// + /// The final area within the parent that element should use to + /// arrange itself and its child elements. + protected override void ArrangeCore(Rect finalRect) + { + base.ArrangeCore(finalRect); + + // Remember arranged size to arrange + // targets in GalleryPanel lately + this.ArrangedSize = finalRect.Size; + } + + #endregion + + #region Debug + + /* FOR DEGUG + protected override void OnRender(DrawingContext drawingContext) + { + drawingContext.DrawRectangle(null, new Pen(Brushes.Red, 1), new Rect(RenderSize)); + }*/ + + #endregion + } +} diff --git a/Fluent/Controls/GalleryPanel.cs b/Fluent.Ribbon/Controls/GalleryPanel.cs similarity index 84% rename from Fluent/Controls/GalleryPanel.cs rename to Fluent.Ribbon/Controls/GalleryPanel.cs index e34ca5453..43ac73538 100644 --- a/Fluent/Controls/GalleryPanel.cs +++ b/Fluent.Ribbon/Controls/GalleryPanel.cs @@ -1,623 +1,620 @@ -namespace Fluent -{ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Media; - using System.Windows.Threading; - - /// - /// Represents panel for Gallery, InRibbonGallery, ComboBox - /// with grouping and filtering capabilities - /// - public class GalleryPanel : VirtualizingStackPanel - { - #region Fields - - // Currently used group containers - private readonly List galleryGroupContainers = new List(); - - // Designate that gallery panel must be refreshed its groups - private bool haveToBeRefreshed; - - // Group name resolver - private Func groupByAdvanced; - - #endregion - - #region Properties - - #region IsGrouped - - /// - /// Gets or sets whether gallery panel shows groups - /// (Filter property still works as usual) - /// - public bool IsGrouped - { - get { return (bool)this.GetValue(IsGroupedProperty); } - set { this.SetValue(IsGroupedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsGrouped. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsGroupedProperty = - DependencyProperty.Register("IsGrouped", typeof(bool), typeof(GalleryPanel), - new UIPropertyMetadata(true, OnIsGroupedChanged)); - - private static void OnIsGroupedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var galleryPanel = (GalleryPanel)d; - galleryPanel.Invalidate(); - } - - #endregion - - #region GroupBy - - /// - /// Gets or sets property name to group items - /// - public string GroupBy - { - get { return (string)this.GetValue(GroupByProperty); } - set { this.SetValue(GroupByProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupBy. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupByProperty = - DependencyProperty.Register("GroupBy", typeof(string), typeof(GalleryPanel), - new UIPropertyMetadata(null, OnGroupByChanged)); - - private static void OnGroupByChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var galleryPanel = (GalleryPanel)d; - galleryPanel.Invalidate(); - } - - #endregion - - #region GroupByAdvanced - - /// - /// Gets or sets custom user method to group items. - /// If this property is not null, GroupBy property is ignored - /// - public Func GroupByAdvanced - { - get { return this.groupByAdvanced; } - set - { - this.groupByAdvanced = value; - this.Invalidate(); - } - } - - #endregion - - #region GroupStyle - - /// - /// Gets or sets group style - /// - public Style GroupStyle - { - get { return (Style)this.GetValue(GroupStyleProperty); } - set { this.SetValue(GroupStyleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupHeaderStyle. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupStyleProperty = - DependencyProperty.Register("GroupHeaderStyle", typeof(Style), - typeof(GalleryPanel), new UIPropertyMetadata(null)); - - #endregion - - #region ItemWidth - - /// - /// Gets or sets a value that specifies the width of - /// all items that are contained within - /// - public double ItemWidth - { - get { return (double)this.GetValue(ItemWidthProperty); } - set { this.SetValue(ItemWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemWidth. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemWidthProperty = - DependencyProperty.Register("ItemWidth", typeof(double), - typeof(GalleryPanel), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ItemHeight - - /// - /// Gets or sets a value that specifies the height of - /// all items that are contained within - /// - public double ItemHeight - { - get { return (double)this.GetValue(ItemHeightProperty); } - set { this.SetValue(ItemHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemHeight. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), - typeof(GalleryPanel), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region Filter - - /// - /// Gets or sets groups names separated by comma which must be shown - /// - public string Filter - { - get { return (string)this.GetValue(FilterProperty); } - set { this.SetValue(FilterProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Filter. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty FilterProperty = - DependencyProperty.Register("Filter", typeof(string), - typeof(GalleryPanel), new UIPropertyMetadata(null, OnFilterChanged)); - - private static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var galleryPanel = (GalleryPanel)d; - galleryPanel.Invalidate(); - } - - #endregion - - #region MinItemsInRow - - /// - /// Gets or sets maximum items quantity in row - /// - public int MinItemsInRow - { - get { return (int)this.GetValue(MinItemsInRowProperty); } - set { this.SetValue(MinItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinItemsInRowProperty = - DependencyProperty.Register("MinItemsInRow", typeof(int), - typeof(GalleryPanel), new UIPropertyMetadata((int)1)); - - #endregion - - #region MaxItemsInRow - - /// - /// Gets or sets maximum items quantity in row - /// - public int MaxItemsInRow - { - get { return (int)this.GetValue(MaxItemsInRowProperty); } - set { this.SetValue(MaxItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxItemsInRowProperty = - DependencyProperty.Register("MaxItemsInRow", typeof(int), - typeof(GalleryPanel), new UIPropertyMetadata(int.MaxValue)); - - #endregion - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public GalleryPanel() - { - this.visualCollection = new VisualCollection(this); - } - - #endregion - - #region Visual Tree - - readonly VisualCollection visualCollection; - - /// - /// Gets the number of visual child elements within this element. - /// - protected override int VisualChildrenCount - { - get - { - return base.VisualChildrenCount + this.visualCollection.Count; - } - } - - /// - /// Overrides System.Windows.Media.Visual.GetVisualChild(System.Int32), - /// and returns a child at the specified index from a collection of child elements. - /// - /// The zero-based index of the requested - /// child element in the collection - /// The requested child element. This should not return null; - /// if the provided index is out of range, an exception is thrown - protected override Visual GetVisualChild(int index) - { - if (index < base.VisualChildrenCount) - { - return base.GetVisualChild(index); - } - - return this.visualCollection[index - base.VisualChildrenCount]; - } - - #endregion - - #region GetActualMinWidth - - /// - /// Updates MinWidth and MaxWidth of the gallery panel (based on MinItemsInRow and MaxItemsInRow) - /// - public void UpdateMinAndMaxWidth() - { - // Calculate actual min width - double actualMinWidth = 0; - var actualMaxWidth = double.PositiveInfinity; - - foreach (var galleryGroupContainer in this.galleryGroupContainers) - { - var backupMinItemsInRow = galleryGroupContainer.MinItemsInRow; - var backupMaxItemsInRow = galleryGroupContainer.MaxItemsInRow; - galleryGroupContainer.MinItemsInRow = this.MinItemsInRow; - galleryGroupContainer.MaxItemsInRow = this.MaxItemsInRow; - - InvalidateMeasureRecursive(galleryGroupContainer); - galleryGroupContainer.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - - galleryGroupContainer.InvalidateMeasure(); - - actualMinWidth = Math.Max(actualMinWidth, galleryGroupContainer.MinWidth); - actualMaxWidth = Math.Min(actualMaxWidth, galleryGroupContainer.MaxWidth); - - galleryGroupContainer.MinItemsInRow = backupMinItemsInRow; - galleryGroupContainer.MaxItemsInRow = backupMaxItemsInRow; - } - - this.MinWidth = actualMinWidth; - this.MaxWidth = actualMaxWidth; - } - - private static void InvalidateMeasureRecursive(UIElement visual) - { - visual.InvalidateMeasure(); - - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++) - { - var element = VisualTreeHelper.GetChild(visual, i) as UIElement; - if (element != null) - { - InvalidateMeasureRecursive(element); - } - } - } - - #endregion - - #region GetItemSize - - /// - /// Determinates item's size (return Size.Empty in case of it is not possible) - /// - /// - public Size GetItemSize() - { - foreach (var galleryGroupContainer in this.galleryGroupContainers) - { - var size = galleryGroupContainer.GetItemSize(); - if (size.IsEmpty == false) - { - return size; - } - } - - return Size.Empty; - } - - #endregion - - #region Refresh - - private void Invalidate() - { - if (this.haveToBeRefreshed) - { - return; - } - - this.haveToBeRefreshed = true; - this.Dispatcher.BeginInvoke((Action)this.RefreshDispatchered, DispatcherPriority.Send); - } - - private void RefreshDispatchered() - { - if (this.haveToBeRefreshed == false) - { - return; - } - - this.Refresh(); - this.haveToBeRefreshed = false; - } - - private void Refresh() - { - // Clear currently used group containers - // and supply with new generated ones - foreach (var galleryGroupContainer in this.galleryGroupContainers) - { - BindingOperations.ClearAllBindings(galleryGroupContainer); - //RemoveVisualChild(galleryGroupContainer); - this.visualCollection.Remove(galleryGroupContainer); - } - - this.galleryGroupContainers.Clear(); - - // Gets filters - var filter = this.Filter == null ? null : this.Filter.Split(','); - - var dictionary = new Dictionary(); - - foreach(UIElement item in this.InternalChildren) - { - if (item == null) - { - continue; - } - - // Resolve group name - string propertyValue = null; - - if (this.GroupByAdvanced == null) - { - propertyValue = (this.ItemContainerGenerator == null) - ? this.GetPropertyValueAsString(item) - : this.GetPropertyValueAsString(this.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this).ItemFromContainer(item)); - } - else - { - propertyValue = (this.ItemContainerGenerator == null) - ? this.GroupByAdvanced(item) - : this.GroupByAdvanced(this.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this).ItemFromContainer(item)); - } - - if (propertyValue == null) - { - propertyValue = "Undefined"; - } - - // Make invisible if it is not in filter (or is not grouped) - if (this.IsGrouped == false - || (filter != null && filter.Contains(propertyValue) == false)) - { - item.Measure(new Size(0,0)); - item.Arrange(new Rect(0,0,0,0)); - } - - // Skip if it is not in filter - if (filter != null && - filter.Contains(propertyValue) == false) - { - continue; - } - - // To put all items in one group in case of IsGrouped = False - if (this.IsGrouped == false) - { - propertyValue = "Undefined"; - } - - if (dictionary.ContainsKey(propertyValue) == false) - { - var galleryGroupContainer = new GalleryGroupContainer - { - Header = propertyValue - }; - RibbonControl.Bind(this, galleryGroupContainer, "GroupStyle", GroupStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, galleryGroupContainer, "Orientation", GalleryGroupContainer.OrientationProperty, BindingMode.OneWay); - RibbonControl.Bind(this, galleryGroupContainer, "ItemWidth", GalleryGroupContainer.ItemWidthProperty, BindingMode.OneWay); - RibbonControl.Bind(this, galleryGroupContainer, "ItemHeight", GalleryGroupContainer.ItemHeightProperty, BindingMode.OneWay); - RibbonControl.Bind(this, galleryGroupContainer, "MaxItemsInRow", GalleryGroupContainer.MaxItemsInRowProperty, BindingMode.OneWay); - RibbonControl.Bind(this, galleryGroupContainer, "MinItemsInRow", GalleryGroupContainer.MinItemsInRowProperty, BindingMode.OneWay); - dictionary.Add(propertyValue,galleryGroupContainer); - this.galleryGroupContainers.Add(galleryGroupContainer); - - this.visualCollection.Add(galleryGroupContainer); - } - - dictionary[propertyValue].Items.Add(new GalleryItemPlaceholder(item)); - } - - if ((this.IsGrouped == false || (this.GroupBy == null && this.GroupByAdvanced == null)) - && this.galleryGroupContainers.Count != 0) - { - // Make it without headers - this.galleryGroupContainers[0].IsHeadered = false; - } - - this.InvalidateMeasure(); - } - - #endregion - - #region Layout Overrides - - /// - /// When overridden in a derived class, measures the size in - /// layout required for child elements and determines a size - /// for the derived class. - /// - /// - /// The size that this element determines it needs during layout, - /// based on its calculations of child element sizes. - /// - /// The available size that this element can give - /// to child elements. Infinity can be specified as a value to indicate that - /// the element will size to whatever content is available. - protected override Size MeasureOverride(Size availableSize) - { - var baseSize = base.MeasureOverride(availableSize); - - if (this.galleryGroupContainers.Count == 0) - { - return baseSize; - } - - double width = 0; - double height = 0; - foreach (var child in this.galleryGroupContainers) - { - child.Measure(availableSize); - height += child.DesiredSize.Height; - width = Math.Max(width, child.DesiredSize.Width); - } - - return new Size(width, height); - } - - /// - /// When overridden in a derived class, positions child elements - /// and determines a size for a derived class. - /// - /// The actual size used. - /// The final area within the parent that this - /// element should use to arrange itself and its children. - protected override Size ArrangeOverride(Size finalSize) - { - var baseSize = base.ArrangeOverride(finalSize); - - if (this.galleryGroupContainers.Count == 0) - { - return baseSize; - } - - var finalRect = new Rect(finalSize); - - foreach (var item in this.galleryGroupContainers) - { - finalRect.Height = item.DesiredSize.Height; - finalRect.Width = Math.Max(finalSize.Width, item.DesiredSize.Width); - - // Arrange a container to arrange placeholders - item.Arrange(finalRect); - - finalRect.Y += item.DesiredSize.Height; - - // Now arrange our actual items using arranged size of placeholders - foreach (GalleryItemPlaceholder placeholder in item.Items) - { - var leftTop = placeholder.TranslatePoint(new Point(), this); - - placeholder.Target.Arrange(new Rect(leftTop.X, leftTop.Y, - placeholder.ArrangedSize.Width, - placeholder.ArrangedSize.Height)); - } - } - - return finalSize; - } - - #endregion - - #region Private Methods - - private string GetPropertyValueAsString(object item) - { - if (item == null || - this.GroupBy == null) - { - return "Undefined"; - } - - var property = item.GetType().GetProperty(this.GroupBy, BindingFlags.Public | BindingFlags.Instance); - if (property == null) - { - return "Undefined"; - } - - var result = property.GetValue(item, null); - if (result == null) - { - return "Undefined"; - } - return result.ToString(); - } - - #endregion - - /// - /// Gets an enumerator that can iterate the logical child elements of this element. - /// - /// - /// An . This property has no default value. - /// - protected override IEnumerator LogicalChildren - { - get - { - var count = this.VisualChildrenCount; - - for (var i = 0; i < count; i++) - { - yield return this.GetVisualChild(i); - } - } - } - - /// - /// Called when the collection that is associated with the for this changes. - /// - /// The that raised the event.Provides data for the event. - protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) - { - base.OnItemsChanged(sender, args); - - this.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)(this.Refresh)); - } - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Media; + using System.Windows.Threading; + using Fluent.Internal; + + /// + /// Represents panel for Gallery, InRibbonGallery, ComboBox + /// with grouping and filtering capabilities + /// + public class GalleryPanel : VirtualizingStackPanel + { + #region Fields + + // Currently used group containers + private readonly List galleryGroupContainers = new List(); + + // Designate that gallery panel must be refreshed its groups + private bool needsRefresh = true; + + // Group name resolver + private Func groupByAdvanced; + + #endregion + + #region Properties + + #region IsGrouped + + /// + /// Gets or sets whether gallery panel shows groups + /// (Filter property still works as usual) + /// + public bool IsGrouped + { + get { return (bool)this.GetValue(IsGroupedProperty); } + set { this.SetValue(IsGroupedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsGrouped. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsGroupedProperty = + DependencyProperty.Register("IsGrouped", typeof(bool), typeof(GalleryPanel), new UIPropertyMetadata(true, OnIsGroupedChanged)); + + private static void OnIsGroupedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var galleryPanel = (GalleryPanel)d; + galleryPanel.Invalidate(); + } + + #endregion + + #region GroupBy + + /// + /// Gets or sets property name to group items + /// + public string GroupBy + { + get { return (string)this.GetValue(GroupByProperty); } + set { this.SetValue(GroupByProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupBy. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupByProperty = + DependencyProperty.Register("GroupBy", typeof(string), typeof(GalleryPanel), new UIPropertyMetadata(null, OnGroupByChanged)); + + private static void OnGroupByChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var galleryPanel = (GalleryPanel)d; + galleryPanel.Invalidate(); + } + + #endregion + + #region GroupByAdvanced + + /// + /// Gets or sets custom user method to group items. + /// If this property is not null, GroupBy property is ignored + /// + public Func GroupByAdvanced + { + get { return this.groupByAdvanced; } + set + { + this.groupByAdvanced = value; + this.Invalidate(); + } + } + + #endregion + + #region GroupStyle + + /// + /// Gets or sets group style + /// + public Style GroupStyle + { + get { return (Style)this.GetValue(GroupStyleProperty); } + set { this.SetValue(GroupStyleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupHeaderStyle. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupStyleProperty = + DependencyProperty.Register("GroupHeaderStyle", typeof(Style), typeof(GalleryPanel), new UIPropertyMetadata(null)); + + #endregion + + #region ItemWidth + + /// + /// Gets or sets a value that specifies the width of + /// all items that are contained within + /// + public double ItemWidth + { + get { return (double)this.GetValue(ItemWidthProperty); } + set { this.SetValue(ItemWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemWidth. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemWidthProperty = + DependencyProperty.Register("ItemWidth", typeof(double), typeof(GalleryPanel), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ItemHeight + + /// + /// Gets or sets a value that specifies the height of + /// all items that are contained within + /// + public double ItemHeight + { + get { return (double)this.GetValue(ItemHeightProperty); } + set { this.SetValue(ItemHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemHeight. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), typeof(GalleryPanel), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region Filter + + /// + /// Gets or sets groups names separated by comma which must be shown + /// + public string Filter + { + get { return (string)this.GetValue(FilterProperty); } + set { this.SetValue(FilterProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Filter. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty FilterProperty = + DependencyProperty.Register("Filter", typeof(string), typeof(GalleryPanel), new UIPropertyMetadata(null, OnFilterChanged)); + + private static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var galleryPanel = (GalleryPanel)d; + galleryPanel.Invalidate(); + } + + #endregion + + #region MinItemsInRow + + /// + /// Gets or sets maximum items quantity in row + /// + public int MinItemsInRow + { + get { return (int)this.GetValue(MinItemsInRowProperty); } + set { this.SetValue(MinItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinItemsInRowProperty = + DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(GalleryPanel), new UIPropertyMetadata(1)); + + #endregion + + #region MaxItemsInRow + + /// + /// Gets or sets maximum items quantity in row + /// + public int MaxItemsInRow + { + get { return (int)this.GetValue(MaxItemsInRowProperty); } + set { this.SetValue(MaxItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxItemsInRowProperty = + DependencyProperty.Register("MaxItemsInRow", typeof(int), typeof(GalleryPanel), new UIPropertyMetadata(int.MaxValue)); + + #endregion + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public GalleryPanel() + { + this.visualCollection = new VisualCollection(this); + } + + #endregion + + #region Visual Tree + + private readonly VisualCollection visualCollection; + private ItemContainerGeneratorAction itemContainerGeneratorAction; + + /// + /// Gets the number of visual child elements within this element. + /// + protected override int VisualChildrenCount + { + get + { + return base.VisualChildrenCount + this.visualCollection.Count; + } + } + + /// + /// Overrides System.Windows.Media.Visual.GetVisualChild(System.Int32), + /// and returns a child at the specified index from a collection of child elements. + /// + /// The zero-based index of the requested + /// child element in the collection + /// The requested child element. This should not return null; + /// if the provided index is out of range, an exception is thrown + protected override Visual GetVisualChild(int index) + { + if (index < base.VisualChildrenCount) + { + return base.GetVisualChild(index); + } + + return this.visualCollection[index - base.VisualChildrenCount]; + } + + #endregion + + #region GetActualMinWidth + + /// + /// Updates MinWidth and MaxWidth of the gallery panel (based on MinItemsInRow and MaxItemsInRow) + /// + public void UpdateMinAndMaxWidth() + { + // Calculate actual min width + double actualMinWidth = 0; + var actualMaxWidth = double.PositiveInfinity; + + foreach (var galleryGroupContainer in this.galleryGroupContainers) + { + var backupMinItemsInRow = galleryGroupContainer.MinItemsInRow; + var backupMaxItemsInRow = galleryGroupContainer.MaxItemsInRow; + galleryGroupContainer.MinItemsInRow = this.MinItemsInRow; + galleryGroupContainer.MaxItemsInRow = this.MaxItemsInRow; + + InvalidateMeasureRecursive(galleryGroupContainer); + galleryGroupContainer.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + galleryGroupContainer.InvalidateMeasure(); + + actualMinWidth = Math.Max(actualMinWidth, galleryGroupContainer.MinWidth); + actualMaxWidth = Math.Min(actualMaxWidth, galleryGroupContainer.MaxWidth); + + galleryGroupContainer.MinItemsInRow = backupMinItemsInRow; + galleryGroupContainer.MaxItemsInRow = backupMaxItemsInRow; + } + + this.MinWidth = actualMinWidth; + this.MaxWidth = actualMaxWidth; + } + + private static void InvalidateMeasureRecursive(UIElement visual) + { + visual.InvalidateMeasure(); + + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++) + { + var element = VisualTreeHelper.GetChild(visual, i) as UIElement; + if (element != null) + { + InvalidateMeasureRecursive(element); + } + } + } + + #endregion + + #region GetItemSize + + /// + /// Determinates item's size (return Size.Empty in case of it is not possible) + /// + /// + public Size GetItemSize() + { + foreach (var galleryGroupContainer in this.galleryGroupContainers) + { + var size = galleryGroupContainer.GetItemSize(); + if (size.IsEmpty == false) + { + return size; + } + } + + return Size.Empty; + } + + #endregion + + #region Refresh + + private void Invalidate() + { + if (this.needsRefresh) + { + return; + } + + this.needsRefresh = true; + this.Dispatcher.BeginInvoke((Action)this.Refresh, DispatcherPriority.Send); + } + + private void Refresh() + { + if (this.needsRefresh == false) + { + return; + } + + this.needsRefresh = false; + + if (this.itemContainerGeneratorAction == null) + { + this.itemContainerGeneratorAction = new ItemContainerGeneratorAction((ItemContainerGenerator)this.ItemContainerGenerator, this.Refresh); + } + + // Clear currently used group containers + // and supply with new generated ones + foreach (var galleryGroupContainer in this.galleryGroupContainers) + { + BindingOperations.ClearAllBindings(galleryGroupContainer); + this.visualCollection.Remove(galleryGroupContainer); + } + + this.galleryGroupContainers.Clear(); + + // Gets filters + var filter = this.Filter?.Split(','); + + var dictionary = new Dictionary(); + + foreach (UIElement item in this.InternalChildren) + { + if (item == null) + { + continue; + } + + // Resolve group name + string propertyValue = null; + + if (this.GroupByAdvanced == null) + { + propertyValue = this.ItemContainerGenerator == null + ? this.GetPropertyValueAsString(item) + : this.GetPropertyValueAsString(this.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this).ItemFromContainer(item)); + } + else + { + propertyValue = this.ItemContainerGenerator == null + ? this.GroupByAdvanced(item) + : this.GroupByAdvanced(this.ItemContainerGenerator.GetItemContainerGeneratorForPanel(this).ItemFromContainer(item)); + } + + if (propertyValue == null) + { + propertyValue = "Undefined"; + } + + // Make invisible if it is not in filter + if (this.IsGrouped + && filter != null + && filter.Contains(propertyValue) == false) + { + item.Visibility = Visibility.Collapsed; + continue; + } + + // Make all not filtered items visible + item.Visibility = Visibility.Visible; + + // To put all items in one group in case of IsGrouped = False + if (this.IsGrouped == false) + { + propertyValue = "Undefined"; + } + + if (dictionary.ContainsKey(propertyValue) == false) + { + var galleryGroupContainer = new GalleryGroupContainer + { + Header = propertyValue + }; + + RibbonControl.Bind(this, galleryGroupContainer, "GroupStyle", GroupStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, galleryGroupContainer, "Orientation", GalleryGroupContainer.OrientationProperty, BindingMode.OneWay); + RibbonControl.Bind(this, galleryGroupContainer, "ItemWidth", GalleryGroupContainer.ItemWidthProperty, BindingMode.OneWay); + RibbonControl.Bind(this, galleryGroupContainer, "ItemHeight", GalleryGroupContainer.ItemHeightProperty, BindingMode.OneWay); + RibbonControl.Bind(this, galleryGroupContainer, "MaxItemsInRow", GalleryGroupContainer.MaxItemsInRowProperty, BindingMode.OneWay); + RibbonControl.Bind(this, galleryGroupContainer, "MinItemsInRow", GalleryGroupContainer.MinItemsInRowProperty, BindingMode.OneWay); + dictionary.Add(propertyValue, galleryGroupContainer); + this.galleryGroupContainers.Add(galleryGroupContainer); + + this.visualCollection.Add(galleryGroupContainer); + } + + dictionary[propertyValue].Items.Add(new GalleryItemPlaceholder(item)); + } + + if ((this.IsGrouped == false || (this.GroupBy == null && this.GroupByAdvanced == null)) + && this.galleryGroupContainers.Count != 0) + { + // Make it without headers + this.galleryGroupContainers[0].IsHeadered = false; + } + + this.InvalidateMeasure(); + } + + #endregion + + #region Layout Overrides + + /// + /// When overridden in a derived class, measures the size in + /// layout required for child elements and determines a size + /// for the derived class. + /// + /// + /// The size that this element determines it needs during layout, + /// based on its calculations of child element sizes. + /// + /// The available size that this element can give + /// to child elements. Infinity can be specified as a value to indicate that + /// the element will size to whatever content is available. + protected override Size MeasureOverride(Size availableSize) + { + var baseSize = base.MeasureOverride(availableSize); + + this.Refresh(); + + if (this.galleryGroupContainers.Count == 0) + { + return baseSize; + } + + double width = 0; + double height = 0; + + foreach (var child in this.galleryGroupContainers) + { + child.Measure(availableSize); + height += child.DesiredSize.Height; + width = Math.Max(width, child.DesiredSize.Width); + } + + return new Size(width, height); + } + + /// + /// When overridden in a derived class, positions child elements + /// and determines a size for a derived class. + /// + /// The actual size used. + /// The final area within the parent that this + /// element should use to arrange itself and its children. + protected override Size ArrangeOverride(Size finalSize) + { + var baseSize = base.ArrangeOverride(finalSize); + + this.Refresh(); + + if (this.galleryGroupContainers.Count == 0) + { + return baseSize; + } + + var finalRect = new Rect(finalSize); + + foreach (var item in this.galleryGroupContainers) + { + finalRect.Height = item.DesiredSize.Height; + finalRect.Width = Math.Max(finalSize.Width, item.DesiredSize.Width); + + // Arrange a container to arrange placeholders + item.Arrange(finalRect); + + finalRect.Y += item.DesiredSize.Height; + + // Now arrange our actual items using arranged size of placeholders + foreach (GalleryItemPlaceholder placeholder in item.Items) + { + var leftTop = placeholder.TranslatePoint(new Point(), this); + + placeholder.Target.Arrange(new Rect(leftTop.X, leftTop.Y, + placeholder.ArrangedSize.Width, + placeholder.ArrangedSize.Height)); + } + } + + return finalSize; + } + + #endregion + + #region Private Methods + + private string GetPropertyValueAsString(object item) + { + if (item == null || + this.GroupBy == null) + { + return "Undefined"; + } + + var property = item.GetType().GetProperty(this.GroupBy, BindingFlags.Public | BindingFlags.Instance); + + var result = property?.GetValue(item, null); + if (result == null) + { + return "Undefined"; + } + + return result.ToString(); + } + + #endregion + + /// + /// Gets an enumerator that can iterate the logical child elements of this element. + /// + /// + /// An . This property has no default value. + /// + protected override IEnumerator LogicalChildren + { + get + { + var count = this.VisualChildrenCount; + + for (var i = 0; i < count; i++) + { + yield return this.GetVisualChild(i); + } + } + } + + /// + /// Called when the collection that is associated with the for this changes. + /// + /// The that raised the event.Provides data for the event. + protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) + { + if (this.itemContainerGeneratorAction?.IsWaitingForGenerator == false) + { + this.itemContainerGeneratorAction?.QueueAction(); + } + + base.OnItemsChanged(sender, args); + } + } } \ No newline at end of file diff --git a/Fluent/Controls/GroupSeparatorMenuItem.cs b/Fluent.Ribbon/Controls/GroupSeparatorMenuItem.cs similarity index 64% rename from Fluent/Controls/GroupSeparatorMenuItem.cs rename to Fluent.Ribbon/Controls/GroupSeparatorMenuItem.cs index 2386256da..42b6bef4e 100644 --- a/Fluent/Controls/GroupSeparatorMenuItem.cs +++ b/Fluent.Ribbon/Controls/GroupSeparatorMenuItem.cs @@ -1,50 +1,40 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represents group separator menu item - /// - [ContentProperty("Header")] - public class GroupSeparatorMenuItem: MenuItem - { - [SuppressMessage("Microsoft.Performance", "CA1810")] - static GroupSeparatorMenuItem() - { - Type type = typeof (GroupSeparatorMenuItem); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - IsEnabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); - IsTabStopProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); - } - - static object CoerceIsEnabledAndTabStop(DependencyObject d, object basevalue) - { - return false; - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(GroupSeparatorMenuItem)); - } - - return basevalue; - } - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents group separator menu item + /// + [ContentProperty("Header")] + public class GroupSeparatorMenuItem: MenuItem + { + [SuppressMessage("Microsoft.Performance", "CA1810")] + static GroupSeparatorMenuItem() + { + var type = typeof (GroupSeparatorMenuItem); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + IsEnabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); + IsTabStopProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); + } + + private static object CoerceIsEnabledAndTabStop(DependencyObject d, object basevalue) + { + return false; + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(GroupSeparatorMenuItem)); + } + + return basevalue; + } + } +} \ No newline at end of file diff --git a/Fluent/Controls/InRibbonGallery.cs b/Fluent.Ribbon/Controls/InRibbonGallery.cs similarity index 83% rename from Fluent/Controls/InRibbonGallery.cs rename to Fluent.Ribbon/Controls/InRibbonGallery.cs index f91dcd3fe..86f3651aa 100644 --- a/Fluent/Controls/InRibbonGallery.cs +++ b/Fluent.Ribbon/Controls/InRibbonGallery.cs @@ -1,1526 +1,1635 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Collections; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Threading; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Input; - using System.Windows.Markup; - using System.Windows.Media; - using System.Windows.Media.Imaging; - using System.Windows.Threading; - using Fluent.Extensibility; - using Fluent.Internal; - - /// - /// Represents the In-Ribbon Gallery, a gallery-based control that exposes - /// a default subset of items directly in the Ribbon. Any remaining items - /// are displayed when a drop-down menu button is clicked - /// - [ContentProperty("Items")] - [SuppressMessage("Microsoft.Maintainability", "CA1506")] - public class InRibbonGallery : Selector, IScalableRibbonControl, IDropDownControl, IRibbonControl, IQuickAccessItemProvider, IRibbonSizeChangedSink - { - #region Fields - - private ObservableCollection filters; - - private ToggleButton expandButton; - private ToggleButton dropDownButton; - - private Panel menuPanel; - - // Freezed image (created during snapping) - private Image snappedImage; - - // Is visual currently snapped - private bool isSnapped; - - private Popup popup; - - // Thumb to resize in both directions - private Thumb resizeBothThumb; - - // Thumb to resize vertical - private Thumb resizeVerticalThumb; - - private DropDownButton groupsMenuButton; - - private GalleryPanel galleryPanel; - - private ContentControl controlPresenter; - private ContentControl popupControlPresenter; - - private ScrollViewer scrollViewer; - - // Needed to prevent drop down reopen - private bool canOpenDropDown = true; - - private IInputElement focusedElement; - - private bool isButtonClicked; - - private FrameworkElement layoutRoot; - - #endregion - - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(InRibbonGallery)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(InRibbonGallery)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(InRibbonGallery)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(InRibbonGallery)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(InRibbonGallery)); - - #endregion - - #region MinItemsInDropDownRow - - /// - /// Min width of the Gallery - /// - public int MinItemsInDropDownRow - { - get { return (int)this.GetValue(MinItemsInDropDownRowProperty); } - set { this.SetValue(MinItemsInDropDownRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MinItemsInDropDownRow. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinItemsInDropDownRowProperty = - DependencyProperty.Register("MinItemsInDropDownRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1)); - - #endregion - - #region MaxItemsInDropDownRow - - /// - /// Max width of the Gallery - /// - public int MaxItemsInDropDownRow - { - get { return (int)this.GetValue(MaxItemsInDropDownRowProperty); } - set { this.SetValue(MaxItemsInDropDownRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxItemsInDropDownRow. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxItemsInDropDownRowProperty = - DependencyProperty.Register("MaxItemsInDropDownRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(int.MaxValue)); - - #endregion - - #region ItemWidth - - /// - /// Gets or sets item width - /// - public double ItemWidth - { - get { return (double)this.GetValue(ItemWidthProperty); } - set { this.SetValue(ItemWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemWidthProperty = - DependencyProperty.Register("ItemWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); - - /// - /// Gets or sets item height - /// - public double ItemHeight - { - get { return (double)this.GetValue(ItemHeightProperty); } - set { this.SetValue(ItemHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region GroupBy - - /// - /// Gets or sets name of property which - /// will use to group items in the Gallery. - /// - public string GroupBy - { - get { return (string)this.GetValue(GroupByProperty); } - set { this.SetValue(GroupByProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupBy. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupByProperty = - DependencyProperty.Register("GroupBy", typeof(string), - typeof(InRibbonGallery), new UIPropertyMetadata(null)); - - #endregion - - #region Orientation - - /// - /// Gets or sets orientation of gallery - /// - public Orientation Orientation - { - get { return (Orientation)this.GetValue(OrientationProperty); } - set { this.SetValue(OrientationProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Orientation. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty OrientationProperty = - DependencyProperty.Register("Orientation", typeof(Orientation), typeof(InRibbonGallery), new UIPropertyMetadata(Orientation.Horizontal)); - - #endregion - - #region Filters - - /// - /// Gets collection of filters - /// - public ObservableCollection Filters - { - get - { - if (this.filters == null) - { - this.filters = new ObservableCollection(); - this.filters.CollectionChanged += this.OnFilterCollectionChanged; - } - return this.filters; - } - } - - // Handle toolbar items changes - private void OnFilterCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.HasFilter = this.Filters.Count > 0; - this.InvalidateProperty(SelectedFilterProperty); - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - foreach (var item in e.NewItems.OfType()) - { - if (this.groupsMenuButton != null) - { - GalleryGroupFilter filter = item; - MenuItem menuItem = new MenuItem(); - menuItem.Header = filter.Title; - menuItem.Tag = filter; - menuItem.IsDefinitive = false; - if (filter == this.SelectedFilter) menuItem.IsChecked = true; - menuItem.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Add(menuItem); - } - } - break; - case NotifyCollectionChangedAction.Remove: - foreach (var item in e.OldItems.OfType()) - { - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item)); - } - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var item in e.OldItems.OfType()) - { - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Remove(this.GetFilterMenuItem(item)); - } - } - foreach (var item in e.NewItems.OfType()) - { - if (this.groupsMenuButton != null) - { - GalleryGroupFilter filter = item; - MenuItem menuItem = new MenuItem(); - menuItem.Header = filter.Title; - menuItem.Tag = filter; - menuItem.IsDefinitive = false; - if (filter == this.SelectedFilter) menuItem.IsChecked = true; - menuItem.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Add(menuItem); - } - } - break; - case NotifyCollectionChangedAction.Reset: - - if (this.groupsMenuButton != null) - { - this.groupsMenuButton.Items.Clear(); - } - - break; - } - } - - /// - /// Gets or sets selected filter - /// - public GalleryGroupFilter SelectedFilter - { - get { return (GalleryGroupFilter)this.GetValue(SelectedFilterProperty); } - set { this.SetValue(SelectedFilterProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectedFilter. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterProperty = - DependencyProperty.Register("SelectedFilter", typeof(GalleryGroupFilter), - typeof(InRibbonGallery), new UIPropertyMetadata(null, OnFilterChanged, CoerceSelectedFilter)); - - // Coerce selected filter - static object CoerceSelectedFilter(DependencyObject d, object basevalue) - { - InRibbonGallery gallery = (InRibbonGallery)d; - if ((basevalue == null) && (gallery.Filters.Count > 0)) return gallery.Filters[0]; - return basevalue; - } - - // Handles filter property changed - static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - InRibbonGallery gallery = (InRibbonGallery)d; - GalleryGroupFilter oldFilter = e.OldValue as GalleryGroupFilter; - if (oldFilter != null) - { - System.Windows.Controls.MenuItem menuItem = gallery.GetFilterMenuItem(oldFilter); - if (menuItem != null) menuItem.IsChecked = false; - } - GalleryGroupFilter filter = e.NewValue as GalleryGroupFilter; - if (filter != null) - { - gallery.SelectedFilterTitle = filter.Title; - gallery.SelectedFilterGroups = filter.Groups; - System.Windows.Controls.MenuItem menuItem = gallery.GetFilterMenuItem(filter); - if (menuItem != null) menuItem.IsChecked = true; - } - else - { - gallery.SelectedFilterTitle = ""; - gallery.SelectedFilterGroups = null; - } - gallery.UpdateLayout(); - } - - /// - /// Gets selected filter title - /// - public string SelectedFilterTitle - { - get { return (string)this.GetValue(SelectedFilterTitleProperty); } - private set { this.SetValue(SelectedFilterTitlePropertyKey, value); } - } - - private static readonly DependencyPropertyKey SelectedFilterTitlePropertyKey = - DependencyProperty.RegisterReadOnly("SelectedFilterTitle", typeof(string), - typeof(InRibbonGallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for SelectedFilterTitle. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterTitleProperty = SelectedFilterTitlePropertyKey.DependencyProperty; - - /// - /// Gets selected filter groups - /// - public string SelectedFilterGroups - { - get { return (string)this.GetValue(SelectedFilterGroupsProperty); } - private set { this.SetValue(SelectedFilterGroupsPropertyKey, value); } - } - - private static readonly DependencyPropertyKey SelectedFilterGroupsPropertyKey = - DependencyProperty.RegisterReadOnly("SelectedFilterGroups", typeof(string), - typeof(InRibbonGallery), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for SelectedFilterGroups. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedFilterGroupsProperty = SelectedFilterGroupsPropertyKey.DependencyProperty; - - /// - /// Gets whether gallery has selected filter - /// - public bool HasFilter - { - get { return (bool)this.GetValue(HasFilterProperty); } - private set { this.SetValue(HasFilterPropertyKey, value); } - } - - private static readonly DependencyPropertyKey HasFilterPropertyKey = DependencyProperty.RegisterReadOnly("HasFilter", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for HasFilter. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasFilterProperty = HasFilterPropertyKey.DependencyProperty; - - void OnFilterMenuItemClick(object sender, RoutedEventArgs e) - { - MenuItem senderItem = (MenuItem)sender; - MenuItem item = this.GetFilterMenuItem(this.SelectedFilter); - item.IsChecked = false; - senderItem.IsChecked = true; - this.SelectedFilter = senderItem.Tag as GalleryGroupFilter; - this.groupsMenuButton.IsDropDownOpen = false; - e.Handled = true; - } - - MenuItem GetFilterMenuItem(GalleryGroupFilter filter) - { - if (filter == null) return null; - if (this.groupsMenuButton == null) return null; - return this.groupsMenuButton.Items.Cast().FirstOrDefault(item => (item != null) && (item.Header.ToString() == filter.Title)); - } - - #endregion - - #region Selectable - - /// - /// Gets or sets whether gallery items can be selected - /// - public bool Selectable - { - get { return (bool)this.GetValue(SelectableProperty); } - set { this.SetValue(SelectableProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Selectable. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectableProperty = - DependencyProperty.Register("Selectable", typeof(bool), - typeof(InRibbonGallery), new UIPropertyMetadata(true, OnSelectableChanged)); - - private static void OnSelectableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - d.CoerceValue(SelectedItemProperty); - } - - #endregion - - #region IsDropDownOpen - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup - { - get { return this.popup; } - } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - /// - /// Gets or sets whether popup is opened - /// - public bool IsDropDownOpen - { - get { return (bool)this.GetValue(IsDropDownOpenProperty); } - set { this.SetValue(IsDropDownOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDropDownOpenProperty = - DependencyProperty.Register("IsDropDownOpen", typeof(bool), - typeof(InRibbonGallery), new UIPropertyMetadata(false)); - - #endregion - - #region ResizeMode - - /// - /// Gets or sets context menu resize mode - /// - public ContextMenuResizeMode ResizeMode - { - get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } - set { this.SetValue(ResizeModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeModeProperty = - DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(InRibbonGallery), new UIPropertyMetadata(ContextMenuResizeMode.None)); - - #endregion - - #region CanCollapseToButton - - /// - /// Gets or sets whether InRibbonGallery - /// - public bool CanCollapseToButton - { - get { return (bool)this.GetValue(CanCollapseToButtonProperty); } - set { this.SetValue(CanCollapseToButtonProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanCollapseToButton. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanCollapseToButtonProperty = - DependencyProperty.Register("CanCollapseToButton", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(true)); - - #endregion - - #region IsCollapsed - - /// - /// Gets whether InRibbonGallery is collapsed to button - /// - public bool IsCollapsed - { - get { return (bool)this.GetValue(IsCollapsedProperty); } - set { this.SetValue(IsCollapsedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsCollapsed. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCollapsedProperty = - DependencyProperty.Register("IsCollapsed", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); - - #endregion - - #region LargeIcon - - /// - /// Button large icon - /// - public ImageSource LargeIcon - { - get { return (ImageSource)this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(ImageSource), typeof(InRibbonGallery), new UIPropertyMetadata(null)); - - #endregion - - #region Snapping - - /// - /// Snaps / Unsnaps the Visual - /// (remove visuals and substitute with freezed image) - /// - public bool IsSnapped - { - get - { - return this.isSnapped; - } - set - { - if (value == this.isSnapped) return; - if (this.IsCollapsed) return; - - if (!this.IsVisible) return; - - if ((value) && (((int)this.ActualWidth > 0) && ((int)this.ActualHeight > 0))) - { - - // Render the freezed image - RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor); - RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)this.galleryPanel.ActualWidth, - (int)this.galleryPanel.ActualHeight, 96, 96, - PixelFormats.Pbgra32); - renderTargetBitmap.Render(this.galleryPanel); - this.snappedImage.Source = renderTargetBitmap; - this.snappedImage.FlowDirection = this.FlowDirection; - this.snappedImage.Width = this.galleryPanel.ActualWidth; - this.snappedImage.Height = this.galleryPanel.ActualHeight; - this.snappedImage.Visibility = Visibility.Visible; - this.isSnapped = value; - } - else - { - this.snappedImage.Visibility = Visibility.Collapsed; - this.isSnapped = value; - this.InvalidateVisual(); - } - - this.InvalidateVisual(); - } - } - - #endregion - - #region Menu - - /// - /// Gets or sets menu to show in combo box bottom - /// - public RibbonMenu Menu - { - get { return (RibbonMenu)this.GetValue(MenuProperty); } - set { this.SetValue(MenuProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MenuProperty = - DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(InRibbonGallery), new UIPropertyMetadata(null)); - - #endregion - - #region Min/Max Sizes - - /// - /// Gets or sets max count of items in row - /// - public int MaxItemsInRow - { - get { return (int)this.GetValue(MaxItemsInRowProperty); } - set { this.SetValue(MaxItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxItemsInRowProperty = - DependencyProperty.Register("MaxItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(8, OnMaxItemsInRowChanged)); - - /// - /// Gets or sets min count of items in row - /// - public int MinItemsInRow - { - get { return (int)this.GetValue(MinItemsInRowProperty); } - set { this.SetValue(MinItemsInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxItemsInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinItemsInRowProperty = - DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1)); - - private static void OnMaxItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - InRibbonGallery gal = d as InRibbonGallery; - int minItemsInRow = (int)e.NewValue; - if (!gal.IsDropDownOpen && (gal.galleryPanel != null) && (gal.galleryPanel.MinItemsInRow < minItemsInRow)) - { - gal.galleryPanel.MinItemsInRow = minItemsInRow; - gal.galleryPanel.MaxItemsInRow = minItemsInRow; - } - } - - #endregion - - #region MaxDropDownHeight - - /// - /// Get or sets max height of drop down popup - /// - public double MaxDropDownHeight - { - get { return (double)this.GetValue(MaxDropDownHeightProperty); } - set { this.SetValue(MaxDropDownHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxDropDownHeightProperty = - DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); - - #endregion - - #region MaxDropDownWidth - - /// - /// Get or sets max width of drop down popup - /// - public double MaxDropDownWidth - { - get { return (double)this.GetValue(MaxDropDownWidthProperty); } - set { this.SetValue(MaxDropDownWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxDropDownWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxDropDownWidthProperty = - DependencyProperty.Register("MaxDropDownWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(SystemParameters.PrimaryScreenWidth / 3.0)); - - #endregion - - #region DropDownHeight - - /// - /// Gets or sets initial dropdown height - /// - public double DropDownHeight - { - get { return (double)this.GetValue(DropDownHeightProperty); } - set { this.SetValue(DropDownHeightProperty, value); } - } - - /// - /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DropDownHeightProperty = - DependencyProperty.Register("DropDownHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region DropDownWidth - - /// - /// Gets or sets initial dropdown width - /// - public double DropDownWidth - { - get { return (double)this.GetValue(DropDownWidthProperty); } - set { this.SetValue(DropDownWidthProperty, value); } - } - - /// - /// /Using a DependencyProperty as the backing store for DropDownWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DropDownWidthProperty = - DependencyProperty.Register("DropDownWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ShowPopupOnTop - - /// - /// Gets a value indicating whether popup is shown on top; - /// - public bool ShowPopupOnTop - { - get { return (bool)this.GetValue(ShowPopupOnTopProperty); } - private set { this.SetValue(ShowPopupOnTopPropertyKey, value); } - } - - // - private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty; - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when control is scaled - /// - public event EventHandler Scaled; - - /// - /// Occurs when context menu is opened - /// - public event EventHandler DropDownOpened; - - /// - /// Occurs when context menu is closed - /// - public event EventHandler DropDownClosed; - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static InRibbonGallery() - { - Type type = typeof(InRibbonGallery); - ToolTipService.Attach(type); - PopupService.Attach(type); - ContextMenuService.Attach(type); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, CoerceSelectedItem)); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(InRibbonGallery)); - } - - return basevalue; - } - - // Coerce selected item - private static object CoerceSelectedItem(DependencyObject d, object basevalue) - { - InRibbonGallery gallery = (InRibbonGallery)d; - if (!gallery.Selectable) - { - GalleryItem galleryItem = (GalleryItem)gallery.ItemContainerGenerator.ContainerFromItem(basevalue); - if (basevalue != null && galleryItem != null) galleryItem.IsSelected = false; - return null; - } - return basevalue; - } - - /// - /// Default constructor - /// - public InRibbonGallery() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region Overrides - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.IsDropDownOpen = true; - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - this.IsDropDownOpen = false; - } - - /// - /// Called when the selection changes. - /// - /// The event data. - protected override void OnSelectionChanged(SelectionChangedEventArgs e) - { - foreach (var item in e.RemovedItems) - { - GalleryItem itemContainer = (this.ItemContainerGenerator.ContainerFromItem(item) as GalleryItem); - if (itemContainer != null) itemContainer.IsSelected = false; - } - - foreach (var item in e.AddedItems) - { - GalleryItem itemContainer = (this.ItemContainerGenerator.ContainerFromItem(item) as GalleryItem); - if (itemContainer != null) itemContainer.IsSelected = true; - } - //if (IsDropDownOpen) IsDropDownOpen = false; - base.OnSelectionChanged(e); - } - - /// - /// When overridden in a derived class, is invoked whenever application - /// code or internal processes call ApplyTemplate - /// - public override void OnApplyTemplate() - { - this.layoutRoot = this.GetTemplateChild("PART_LayoutRoot") as FrameworkElement; - - if (this.expandButton != null) - this.expandButton.Click -= this.OnExpandClick; - this.expandButton = this.GetTemplateChild("PART_ExpandButton") as ToggleButton; - if (this.expandButton != null) - this.expandButton.Click += this.OnExpandClick; - - if (this.dropDownButton != null) - this.dropDownButton.Click -= this.OnDropDownClick; - this.dropDownButton = this.GetTemplateChild("PART_DropDownButton") as ToggleButton; - if (this.dropDownButton != null) - this.dropDownButton.Click += this.OnDropDownClick; - - if (this.popup != null) - { - this.popup.Opened -= this.OnDropDownOpened; - this.popup.Closed -= this.OnDropDownClosed; - - this.popup.PreviewMouseLeftButtonUp -= this.OnPopupPreviewMouseUp; - this.popup.PreviewMouseLeftButtonDown -= this.OnPopupPreviewMouseDown; - } - - this.popup = this.GetTemplateChild("PART_Popup") as Popup; - - if (this.popup != null) - { - this.popup.Opened += this.OnDropDownOpened; - this.popup.Closed += this.OnDropDownClosed; - - this.popup.PreviewMouseLeftButtonUp += this.OnPopupPreviewMouseUp; - this.popup.PreviewMouseLeftButtonDown += this.OnPopupPreviewMouseDown; - - KeyboardNavigation.SetControlTabNavigation(this.popup, KeyboardNavigationMode.Cycle); - KeyboardNavigation.SetDirectionalNavigation(this.popup, KeyboardNavigationMode.Cycle); - KeyboardNavigation.SetTabNavigation(this.popup, KeyboardNavigationMode.Cycle); - } - - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; - } - this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; - } - this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; - } - - this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; - - if (this.groupsMenuButton != null) - this.groupsMenuButton.Items.Clear(); - this.groupsMenuButton = this.GetTemplateChild("PART_FilterDropDownButton") as DropDownButton; - if (this.groupsMenuButton != null) - { - for (int i = 0; i < this.Filters.Count; i++) - { - MenuItem item = new MenuItem(); - item.Header = this.Filters[i].Title; - item.Tag = this.Filters[i]; - item.IsDefinitive = false; - if (this.Filters[i] == this.SelectedFilter) item.IsChecked = true; - item.Click += this.OnFilterMenuItemClick; - this.groupsMenuButton.Items.Add(item); - } - } - - this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel; - - if (this.galleryPanel != null) - { - this.galleryPanel.MinItemsInRow = this.MaxItemsInRow; - this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow; - } - - this.snappedImage = this.GetTemplateChild("PART_FakeImage") as Image; - - this.controlPresenter = this.GetTemplateChild("PART_ContentPresenter") as ContentControl; - this.popupControlPresenter = this.GetTemplateChild("PART_PopupContentPresenter") as ContentControl; - - this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; - } - - private void OnPopupPreviewMouseUp(object sender, MouseButtonEventArgs e) - { - // Ignore mouse up when mouse donw is on expand button - if (this.isButtonClicked) - { - this.isButtonClicked = false; - e.Handled = true; - } - } - - private void OnPopupPreviewMouseDown(object sender, MouseButtonEventArgs e) - { - this.isButtonClicked = false; - } - - private void OnExpandClick(object sender, RoutedEventArgs e) - { - this.isButtonClicked = true; - } - - private void OnDropDownClick(object sender, RoutedEventArgs e) - { - if (this.canOpenDropDown) - this.IsDropDownOpen = true; - } - - // Handles drop down opened - void OnDropDownClosed(object sender, EventArgs e) - { - this.galleryPanel.Width = double.NaN; - this.galleryPanel.IsGrouped = false; - this.galleryPanel.MinItemsInRow = this.MinItemsInRow; - this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow; - this.galleryPanel.UpdateMinAndMaxWidth(); - - this.popupControlPresenter.Content = null; - this.controlPresenter.Content = this.galleryPanel; - this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() => - { - if ((this.quickAccessGallery == null) || ((this.quickAccessGallery != null) && (!this.quickAccessGallery.IsDropDownOpen))) - { - this.IsSnapped = false; - } - })); - - //snappedImage.Visibility = Visibility.Collapsed; - if (this.DropDownClosed != null) - this.DropDownClosed(this, e); - if (Mouse.Captured == this) Mouse.Capture(null); - this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() => - { - GalleryItem selectedContainer = this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as GalleryItem; - if (selectedContainer != null) selectedContainer.BringIntoView(); - - })); - this.dropDownButton.IsChecked = false; - this.canOpenDropDown = true; - } - - // Handles drop down closed - private void OnDropDownOpened(object sender, EventArgs e) - { - this.IsSnapped = true; - - this.controlPresenter.Content = null; - this.popupControlPresenter.Content = this.galleryPanel; - this.galleryPanel.Width = double.NaN; - this.scrollViewer.Height = double.NaN; - - if (this.DropDownOpened != null) - { - this.DropDownOpened(this, e); - } - - this.galleryPanel.MinItemsInRow = this.MinItemsInDropDownRow; - this.galleryPanel.MaxItemsInRow = this.MaxItemsInDropDownRow; - this.galleryPanel.UpdateMinAndMaxWidth(); - - this.galleryPanel.IsGrouped = true; - this.dropDownButton.IsChecked = true; - this.canOpenDropDown = false; - - Mouse.Capture(this, CaptureMode.SubTree); - - this.focusedElement = Keyboard.FocusedElement; - Debug.WriteLine("Focused element - " + this.focusedElement); - - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; - this.focusedElement.PreviewKeyDown += this.OnFocusedElementPreviewKeyDown; - } - - //if (ResizeMode != ContextMenuResizeMode.None) - { - this.scrollViewer.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - - var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height, this.MaxDropDownHeight); - - if (!double.IsNaN(this.DropDownHeight)) - { - initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight); - } - - var initialWidth = Math.Min(RibbonControl.GetControlWorkArea(this).Height, this.MaxDropDownWidth); - - if (!double.IsNaN(this.DropDownWidth)) - { - initialWidth = Math.Min(this.DropDownWidth, this.MaxDropDownWidth); - } - - double menuHeight = 0; - double menuWidth = 0; - - if (this.Menu != null) - { - this.Menu.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - menuHeight = this.Menu.DesiredSize.Height; - menuWidth = this.Menu.DesiredSize.Width; - } - - if (this.scrollViewer.DesiredSize.Height > initialHeight) - { - this.scrollViewer.Height = initialHeight - menuHeight; - - if (this.scrollViewer.Height < this.galleryPanel.GetItemSize().Height) - { - this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height; - } - } - - if (this.scrollViewer.DesiredSize.Width > initialWidth) - { - this.scrollViewer.Width = initialWidth - menuWidth; - - if (this.scrollViewer.Width < this.galleryPanel.GetItemSize().Width) - { - this.scrollViewer.Width = this.galleryPanel.GetItemSize().Width; - } - } - } - } - - /// - /// Handles size property changing - /// - /// Previous value - /// Current value - public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) - { - if (this.CanCollapseToButton) - { - if (current == RibbonControlSize.Large - && this.galleryPanel.MinItemsInRow > this.MinItemsInRow) - { - this.IsCollapsed = false; - } - else - { - this.IsCollapsed = true; - } - } - else - { - this.IsCollapsed = false; - } - } - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new GalleryItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is GalleryItem; - } - - /// - /// Invoked when the event is received. - /// - /// Information about the event. - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.Key == Key.Escape) - { - this.IsDropDownOpen = false; - } - - base.OnKeyDown(e); - } - - private void OnFocusedElementPreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Escape) - { - this.IsDropDownOpen = false; - } - } - - private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; - this.focusedElement.PreviewKeyDown -= this.OnFocusedElementPreviewKeyDown; - } - - #endregion - - #region Private Methods - - // Handles resize both drag - private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) - { - this.OnResizeVerticalDelta(sender, e); - - this.menuPanel.Width = double.NaN; - - if (double.IsNaN(this.galleryPanel.Width)) - { - this.galleryPanel.Width = this.galleryPanel.ActualWidth; - } - - this.galleryPanel.Width = Math.Max(this.layoutRoot.ActualWidth, this.galleryPanel.Width + e.HorizontalChange); - - } - - // Handles resize vertical drag - private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) - { - if (double.IsNaN(this.scrollViewer.Height)) - { - this.scrollViewer.Height = this.scrollViewer.ActualHeight; - } - - this.scrollViewer.Height = Math.Max(this.layoutRoot.ActualHeight, Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); - } - - #endregion - - #region QuickAccess - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - var gallery = new InRibbonGallery(); - RibbonControl.BindQuickAccessItem(this, gallery); - RibbonControl.Bind(this, gallery, "GroupBy", GroupByProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemHeight", ItemHeightProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemWidth", ItemWidthProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ResizeMode", ResizeModeProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "MinItemsInDropDownRow", MinItemsInDropDownRowProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "MaxItemsInDropDownRow", MaxItemsInDropDownRowProperty, BindingMode.OneWay); - - RibbonControl.Bind(this, gallery, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "MaxDropDownWidth", MaxDropDownWidthProperty, BindingMode.OneWay); - RibbonControl.Bind(this, gallery, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); - - gallery.DropDownOpened += this.OnQuickAccessOpened; - if (this.DropDownClosed != null) gallery.DropDownClosed += this.DropDownClosed; - if (this.DropDownOpened != null) gallery.DropDownOpened += this.DropDownOpened; - - RibbonProperties.SetSize(gallery, RibbonControlSize.Small); - this.quickAccessGallery = gallery; - return gallery; - } - - private object selectedItem; - private InRibbonGallery quickAccessGallery; - - private void OnQuickAccessOpened(object sender, EventArgs e) - { - for (var i = 0; i < this.Filters.Count; i++) - { - this.quickAccessGallery.Filters.Add(this.Filters[i]); - } - - this.quickAccessGallery.SelectedFilter = this.SelectedFilter; - - this.quickAccessGallery.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; - this.quickAccessGallery.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; - - this.UpdateLayout(); - this.Dispatcher.BeginInvoke(DispatcherPriority.Render, ((Action)(this.Freeze))); - } - - private void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) - { - this.quickAccessGallery.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; - this.quickAccessGallery.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; - - this.SelectedFilter = this.quickAccessGallery.SelectedFilter; - this.quickAccessGallery.Filters.Clear(); - this.Unfreeze(); - } - - private void Freeze() - { - this.IsSnapped = true; - this.selectedItem = this.SelectedItem; - this.SelectedItem = null; - - ItemsControlHelper.MoveItemsToDifferentControl(this, this.quickAccessGallery); - - this.quickAccessGallery.SelectedItem = this.selectedItem; - this.quickAccessGallery.Menu = this.Menu; - this.Menu = null; - //quickAccessGallery.IsSnapped = false; - } - - private void Unfreeze() - { - this.selectedItem = this.quickAccessGallery.SelectedItem; - //quickAccessGallery.IsSnapped = true; - this.quickAccessGallery.SelectedItem = null; - - ItemsControlHelper.MoveItemsToDifferentControl(this.quickAccessGallery, this); - - this.SelectedItem = this.selectedItem; - this.Menu = this.quickAccessGallery.Menu; - this.quickAccessGallery.Menu = null; - - if (!this.IsDropDownOpen) - { - if (this.controlPresenter != null) - { - this.controlPresenter.Content = null; - } - - if (this.popupControlPresenter != null) - { - this.popupControlPresenter.Content = this.galleryPanel; - } - - if (this.galleryPanel != null) - { - this.galleryPanel.IsGrouped = true; - this.galleryPanel.IsGrouped = false; - } - - if (this.popupControlPresenter != null) - { - this.popupControlPresenter.Content = null; - } - - if (this.controlPresenter != null) - { - this.controlPresenter.Content = this.galleryPanel; - } - } - - this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, ((ThreadStart)(() => - { - if (!this.IsDropDownOpen) - { - this.IsSnapped = false; - } - var selectedContainer = this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as GalleryItem; - if (selectedContainer != null) selectedContainer.BringIntoView(); - }))); - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(InRibbonGallery), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IScalableRibbonControl - - /// - /// Enlarge control size - /// - public void Enlarge() - { - /*currentItemsInRow++; - - if ((CanCollapseToButton) && (CurrentItemsInRow >= MinItemsInRow) && (Size == RibbonControlSize.Large)) IsCollapsed = false; - - InvalidateMeasure();*/ - if (this.IsCollapsed && (RibbonProperties.GetSize(this) == RibbonControlSize.Large)) - this.IsCollapsed = false; - else if (this.galleryPanel.MinItemsInRow < this.MaxItemsInRow) - { - this.galleryPanel.MinItemsInRow++; - this.galleryPanel.MaxItemsInRow = this.galleryPanel.MinItemsInRow; - } - else return; - this.InvalidateMeasure(); - //UpdateLayout(); - if (this.Scaled != null) - this.Scaled(this, EventArgs.Empty); - } - - /// - /// Reduce control size - /// - public void Reduce() - { - if (this.galleryPanel.MinItemsInRow > this.MinItemsInRow) - { - this.galleryPanel.MinItemsInRow--; - this.galleryPanel.MaxItemsInRow = this.galleryPanel.MinItemsInRow; - } - else if (this.CanCollapseToButton && !this.IsCollapsed) - this.IsCollapsed = true; - else return; - this.InvalidateMeasure(); - if (this.Scaled != null) - this.Scaled(this, EventArgs.Empty); - /*currentItemsInRow--; - if ((CanCollapseToButton) && (CurrentItemsInRow < MinItemsInRow)) IsCollapsed = true; - - InvalidateMeasure();*/ - } - - #endregion - - /// - /// Gets an enumerator for the logical child objects of the object. - /// - /// - /// An enumerator for the logical child objects of the object. The default is null. - /// - protected override IEnumerator LogicalChildren - { - get - { - if (this.galleryPanel != null) - { - yield return this.galleryPanel; - } - } - } - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Threading; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Markup; + using System.Windows.Media; + using System.Windows.Media.Imaging; + using System.Windows.Threading; + using Fluent.Extensibility; + using Fluent.Extensions; + using Fluent.Internal; + + /// + /// Represents the In-Ribbon Gallery, a gallery-based control that exposes + /// a default subset of items directly in the Ribbon. Any remaining items + /// are displayed when a drop-down menu button is clicked + /// + [ContentProperty("Items")] + [SuppressMessage("Microsoft.Maintainability", "CA1506")] + public class InRibbonGallery : Selector, IScalableRibbonControl, IDropDownControl, IRibbonControl, IQuickAccessItemProvider, IRibbonSizeChangedSink + { + #region Fields + + private ObservableCollection filters; + + private ToggleButton expandButton; + private ToggleButton dropDownButton; + + private Panel menuPanel; + + // Freezed image (created during snapping) + private Image snappedImage; + + // Is visual currently snapped + private bool isSnapped; + + private Popup popup; + + // Thumb to resize in both directions + private Thumb resizeBothThumb; + + // Thumb to resize vertical + private Thumb resizeVerticalThumb; + + private DropDownButton groupsMenuButton; + + private GalleryPanel galleryPanel; + + private ContentControl controlPresenter; + private ContentControl popupControlPresenter; + + private ScrollViewer scrollViewer; + + // Needed to prevent drop down reopen + private bool canOpenDropDown = true; + + private IInputElement focusedElement; + + private bool isButtonClicked; + + private FrameworkElement layoutRoot; + + #endregion + + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(InRibbonGallery)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(InRibbonGallery)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(InRibbonGallery)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(InRibbonGallery)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(InRibbonGallery)); + + #endregion + + #region MinItemsInDropDownRow + + /// + /// Min width of the Gallery + /// + public int MinItemsInDropDownRow + { + get { return (int)this.GetValue(MinItemsInDropDownRowProperty); } + set { this.SetValue(MinItemsInDropDownRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MinItemsInDropDownRow. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinItemsInDropDownRowProperty = + DependencyProperty.Register("MinItemsInDropDownRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1)); + + #endregion + + #region MaxItemsInDropDownRow + + /// + /// Max width of the Gallery + /// + public int MaxItemsInDropDownRow + { + get { return (int)this.GetValue(MaxItemsInDropDownRowProperty); } + set { this.SetValue(MaxItemsInDropDownRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxItemsInDropDownRow. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxItemsInDropDownRowProperty = + DependencyProperty.Register("MaxItemsInDropDownRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(int.MaxValue)); + + #endregion + + #region ItemWidth + + /// + /// Gets or sets item width + /// + public double ItemWidth + { + get { return (double)this.GetValue(ItemWidthProperty); } + set { this.SetValue(ItemWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemWidthProperty = + DependencyProperty.Register("ItemWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); + + /// + /// Gets or sets item height + /// + public double ItemHeight + { + get { return (double)this.GetValue(ItemHeightProperty); } + set { this.SetValue(ItemHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ItemHeightProperty = + DependencyProperty.Register("ItemHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region GroupBy + + /// + /// Gets or sets name of property which + /// will use to group items in the Gallery. + /// + public string GroupBy + { + get { return (string)this.GetValue(GroupByProperty); } + set { this.SetValue(GroupByProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupBy. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupByProperty = + DependencyProperty.Register("GroupBy", typeof(string), typeof(InRibbonGallery), new UIPropertyMetadata(null)); + + #endregion + + #region Orientation + + /// + /// Gets or sets orientation of gallery + /// + public Orientation Orientation + { + get { return (Orientation)this.GetValue(OrientationProperty); } + set { this.SetValue(OrientationProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Orientation. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register("Orientation", typeof(Orientation), typeof(InRibbonGallery), new UIPropertyMetadata(Orientation.Horizontal)); + + #endregion + + #region Filters + + /// + /// Gets collection of filters + /// + public ObservableCollection Filters + { + get + { + if (this.filters == null) + { + this.filters = new ObservableCollection(); + this.filters.CollectionChanged += this.OnFilterCollectionChanged; + } + + return this.filters; + } + } + + // Handle toolbar items changes + private void OnFilterCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.HasFilter = this.Filters.Count > 0; + this.InvalidateProperty(SelectedFilterProperty); + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (var item in e.NewItems.OfType()) + { + if (this.groupsMenuButton != null) + { + var filter = item; + var menuItem = new MenuItem + { + Header = filter.Title, + Tag = filter, + IsDefinitive = false + }; + + if (ReferenceEquals(filter, this.SelectedFilter)) + { + menuItem.IsChecked = true; + } + + menuItem.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Add(menuItem); + } + } + break; + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems.OfType()) + { + this.groupsMenuButton?.Items.Remove(this.GetFilterMenuItem(item)); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var item in e.OldItems.OfType()) + { + this.groupsMenuButton?.Items.Remove(this.GetFilterMenuItem(item)); + } + + foreach (var item in e.NewItems.OfType()) + { + if (this.groupsMenuButton != null) + { + var filter = item; + var menuItem = new MenuItem + { + Header = filter.Title, + Tag = filter, + IsDefinitive = false + }; + + if (ReferenceEquals(filter, this.SelectedFilter)) + { + menuItem.IsChecked = true; + } + + menuItem.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Add(menuItem); + } + } + break; + case NotifyCollectionChangedAction.Reset: + this.groupsMenuButton?.Items.Clear(); + break; + } + } + + /// + /// Gets or sets selected filter + /// + public GalleryGroupFilter SelectedFilter + { + get { return (GalleryGroupFilter)this.GetValue(SelectedFilterProperty); } + set { this.SetValue(SelectedFilterProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectedFilter. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterProperty = + DependencyProperty.Register("SelectedFilter", typeof(GalleryGroupFilter), typeof(InRibbonGallery), new UIPropertyMetadata(null, OnFilterChanged, CoerceSelectedFilter)); + + // Coerce selected filter + static object CoerceSelectedFilter(DependencyObject d, object basevalue) + { + var gallery = (InRibbonGallery)d; + if (basevalue == null + && gallery.Filters.Count > 0) + { + return gallery.Filters[0]; + } + + return basevalue; + } + + // Handles filter property changed + private static void OnFilterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var gallery = (InRibbonGallery)d; + var oldFilter = e.OldValue as GalleryGroupFilter; + + if (oldFilter != null) + { + System.Windows.Controls.MenuItem menuItem = gallery.GetFilterMenuItem(oldFilter); + + if (menuItem != null) + { + menuItem.IsChecked = false; + } + } + + var filter = e.NewValue as GalleryGroupFilter; + + if (filter != null) + { + gallery.SelectedFilterTitle = filter.Title; + gallery.SelectedFilterGroups = filter.Groups; + System.Windows.Controls.MenuItem menuItem = gallery.GetFilterMenuItem(filter); + + if (menuItem != null) + { + menuItem.IsChecked = true; + } + } + else + { + gallery.SelectedFilterTitle = ""; + gallery.SelectedFilterGroups = null; + } + + gallery.UpdateLayout(); + } + + /// + /// Gets selected filter title + /// + public string SelectedFilterTitle + { + get { return (string)this.GetValue(SelectedFilterTitleProperty); } + private set { this.SetValue(SelectedFilterTitlePropertyKey, value); } + } + + private static readonly DependencyPropertyKey SelectedFilterTitlePropertyKey = + DependencyProperty.RegisterReadOnly("SelectedFilterTitle", typeof(string), typeof(InRibbonGallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for SelectedFilterTitle. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterTitleProperty = SelectedFilterTitlePropertyKey.DependencyProperty; + + /// + /// Gets selected filter groups + /// + public string SelectedFilterGroups + { + get { return (string)this.GetValue(SelectedFilterGroupsProperty); } + private set { this.SetValue(SelectedFilterGroupsPropertyKey, value); } + } + + private static readonly DependencyPropertyKey SelectedFilterGroupsPropertyKey = + DependencyProperty.RegisterReadOnly("SelectedFilterGroups", typeof(string), typeof(InRibbonGallery), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for SelectedFilterGroups. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedFilterGroupsProperty = SelectedFilterGroupsPropertyKey.DependencyProperty; + + /// + /// Gets whether gallery has selected filter + /// + public bool HasFilter + { + get { return (bool)this.GetValue(HasFilterProperty); } + private set { this.SetValue(HasFilterPropertyKey, value); } + } + + private static readonly DependencyPropertyKey HasFilterPropertyKey = DependencyProperty.RegisterReadOnly("HasFilter", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for HasFilter. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasFilterProperty = HasFilterPropertyKey.DependencyProperty; + + private void OnFilterMenuItemClick(object sender, RoutedEventArgs e) + { + var senderItem = (MenuItem)sender; + var item = this.GetFilterMenuItem(this.SelectedFilter); + item.IsChecked = false; + senderItem.IsChecked = true; + this.SelectedFilter = senderItem.Tag as GalleryGroupFilter; + this.groupsMenuButton.IsDropDownOpen = false; + e.Handled = true; + } + + private MenuItem GetFilterMenuItem(GalleryGroupFilter filter) + { + if (filter == null) + { + return null; + } + + return this.groupsMenuButton?.Items.Cast() + .FirstOrDefault(item => item != null && item.Header.ToString() == filter.Title); + } + + #endregion + + #region Selectable + + /// + /// Gets or sets whether gallery items can be selected + /// + public bool Selectable + { + get { return (bool)this.GetValue(SelectableProperty); } + set { this.SetValue(SelectableProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Selectable. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectableProperty = + DependencyProperty.Register("Selectable", typeof(bool), + typeof(InRibbonGallery), new UIPropertyMetadata(true, OnSelectableChanged)); + + private static void OnSelectableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.CoerceValue(SelectedItemProperty); + } + + #endregion + + #region IsDropDownOpen + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup + { + get { return this.popup; } + } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + /// + /// Gets or sets whether popup is opened + /// + public bool IsDropDownOpen + { + get { return (bool)this.GetValue(IsDropDownOpenProperty); } + set { this.SetValue(IsDropDownOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDropDownOpenProperty = + DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); + + #endregion + + #region ResizeMode + + /// + /// Gets or sets context menu resize mode + /// + public ContextMenuResizeMode ResizeMode + { + get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } + set { this.SetValue(ResizeModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeModeProperty = + DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(InRibbonGallery), new UIPropertyMetadata(ContextMenuResizeMode.None)); + + #endregion + + #region CanCollapseToButton + + /// + /// Gets or sets whether InRibbonGallery + /// + public bool CanCollapseToButton + { + get { return (bool)this.GetValue(CanCollapseToButtonProperty); } + set { this.SetValue(CanCollapseToButtonProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanCollapseToButton. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanCollapseToButtonProperty = + DependencyProperty.Register("CanCollapseToButton", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(true)); + + #endregion + + #region IsCollapsed + + /// + /// Gets whether InRibbonGallery is collapsed to button + /// + public bool IsCollapsed + { + get { return (bool)this.GetValue(IsCollapsedProperty); } + set { this.SetValue(IsCollapsedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsCollapsed. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCollapsedProperty = + DependencyProperty.Register("IsCollapsed", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); + + #endregion + + #region LargeIcon + + /// + /// Button large icon + /// + public ImageSource LargeIcon + { + get { return (ImageSource)this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = + DependencyProperty.Register("LargeIcon", typeof(ImageSource), typeof(InRibbonGallery), new UIPropertyMetadata(null)); + + #endregion + + #region Snapping + + /// + /// Snaps / Unsnaps the Visual + /// (remove visuals and substitute with freezed image) + /// + public bool IsSnapped + { + get + { + return this.isSnapped; + } + set + { + if (value == this.isSnapped) + { + return; + } + + if (this.IsCollapsed) + { + return; + } + + if (this.IsVisible == false) + { + return; + } + + if (value + && (int)this.ActualWidth > 0 + && (int)this.ActualHeight > 0) + { + // Render the freezed image + RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor); + var renderTargetBitmap = new RenderTargetBitmap((int)this.galleryPanel.ActualWidth, + (int)this.galleryPanel.ActualHeight, 96, 96, + PixelFormats.Pbgra32); + renderTargetBitmap.Render(this.galleryPanel); + this.snappedImage.Source = renderTargetBitmap; + this.snappedImage.FlowDirection = this.FlowDirection; + this.snappedImage.Width = this.galleryPanel.ActualWidth; + this.snappedImage.Height = this.galleryPanel.ActualHeight; + this.snappedImage.Visibility = Visibility.Visible; + } + else + { + this.snappedImage.Visibility = Visibility.Collapsed; + } + + this.isSnapped = value; + + this.InvalidateVisual(); + } + } + + #endregion + + #region Menu + + /// + /// Gets or sets menu to show in combo box bottom + /// + public RibbonMenu Menu + { + get { return (RibbonMenu)this.GetValue(MenuProperty); } + set { this.SetValue(MenuProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MenuProperty = + DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(InRibbonGallery), new UIPropertyMetadata(null)); + + #endregion + + #region Min/Max Sizes + + /// + /// Gets or sets max count of items in row + /// + public int MaxItemsInRow + { + get { return (int)this.GetValue(MaxItemsInRowProperty); } + set { this.SetValue(MaxItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxItemsInRowProperty = + DependencyProperty.Register("MaxItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(8, OnMaxItemsInRowChanged)); + + private static void OnMaxItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var gal = (InRibbonGallery)d; + var maxItemsInRow = (int)e.NewValue; + + if (gal.IsDropDownOpen == false + && gal.galleryPanel != null + && gal.galleryPanel.MaxItemsInRow < maxItemsInRow) + { + gal.galleryPanel.MaxItemsInRow = maxItemsInRow; + } + } + + /// + /// Gets or sets min count of items in row + /// + public int MinItemsInRow + { + get { return (int)this.GetValue(MinItemsInRowProperty); } + set { this.SetValue(MinItemsInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxItemsInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinItemsInRowProperty = + DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1, OnMinItemsInRowChanged)); + + private static void OnMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var gal = (InRibbonGallery)d; + var minItemsInRow = (int)e.NewValue; + + if (gal.IsDropDownOpen == false + && gal.galleryPanel != null + && gal.galleryPanel.MinItemsInRow > minItemsInRow) + { + gal.galleryPanel.MinItemsInRow = minItemsInRow; + } + } + + #endregion + + #region MaxDropDownHeight + + /// + /// Get or sets max height of drop down popup + /// + public double MaxDropDownHeight + { + get { return (double)this.GetValue(MaxDropDownHeightProperty); } + set { this.SetValue(MaxDropDownHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxDropDownHeightProperty = + DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); + + #endregion + + #region MaxDropDownWidth + + /// + /// Get or sets max width of drop down popup + /// + public double MaxDropDownWidth + { + get { return (double)this.GetValue(MaxDropDownWidthProperty); } + set { this.SetValue(MaxDropDownWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxDropDownWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxDropDownWidthProperty = + DependencyProperty.Register("MaxDropDownWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(SystemParameters.PrimaryScreenWidth / 3.0)); + + #endregion + + #region DropDownHeight + + /// + /// Gets or sets initial dropdown height + /// + public double DropDownHeight + { + get { return (double)this.GetValue(DropDownHeightProperty); } + set { this.SetValue(DropDownHeightProperty, value); } + } + + /// + /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DropDownHeightProperty = + DependencyProperty.Register("DropDownHeight", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region DropDownWidth + + /// + /// Gets or sets initial dropdown width + /// + public double DropDownWidth + { + get { return (double)this.GetValue(DropDownWidthProperty); } + set { this.SetValue(DropDownWidthProperty, value); } + } + + /// + /// /Using a DependencyProperty as the backing store for DropDownWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DropDownWidthProperty = + DependencyProperty.Register("DropDownWidth", typeof(double), typeof(InRibbonGallery), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region ShowPopupOnTop + + /// + /// Gets a value indicating whether popup is shown on top; + /// + public bool ShowPopupOnTop + { + get { return (bool)this.GetValue(ShowPopupOnTopProperty); } + private set { this.SetValue(ShowPopupOnTopPropertyKey, value); } + } + + // + private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(InRibbonGallery), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty; + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when control is scaled + /// + public event EventHandler Scaled; + + /// + /// Occurs when context menu is opened + /// + public event EventHandler DropDownOpened; + + /// + /// Occurs when context menu is closed + /// + public event EventHandler DropDownClosed; + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static InRibbonGallery() + { + var type = typeof(InRibbonGallery); + ToolTipService.Attach(type); + PopupService.Attach(type); + ContextMenuService.Attach(type); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, OnCoerceStyle)); + SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, CoerceSelectedItem)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = ((FrameworkElement)d).TryFindResource(typeof(InRibbonGallery)); + } + + return basevalue; + } + + // Coerce selected item + private static object CoerceSelectedItem(DependencyObject d, object basevalue) + { + var gallery = (InRibbonGallery)d; + + if (gallery.Selectable == false) + { + var galleryItem = (GalleryItem)gallery.ItemContainerGenerator.ContainerFromItem(basevalue); + if (basevalue != null + && galleryItem != null) + { + galleryItem.IsSelected = false; + } + + return null; + } + + return basevalue; + } + + /// + /// Default constructor + /// + public InRibbonGallery() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region Overrides + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.IsDropDownOpen = true; + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + this.IsDropDownOpen = false; + } + + /// + /// Called when the selection changes. + /// + /// The event data. + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + foreach (var item in e.RemovedItems) + { + var itemContainer = this.ItemContainerGenerator.ContainerFromItem(item) as GalleryItem; + if (itemContainer != null) + { + itemContainer.IsSelected = false; + } + } + + foreach (var item in e.AddedItems) + { + var itemContainer = this.ItemContainerGenerator.ContainerFromItem(item) as GalleryItem; + if (itemContainer != null) + { + itemContainer.IsSelected = true; + } + } + + base.OnSelectionChanged(e); + } + + /// + /// When overridden in a derived class, is invoked whenever application + /// code or internal processes call ApplyTemplate + /// + public override void OnApplyTemplate() + { + this.layoutRoot = this.GetTemplateChild("PART_LayoutRoot") as FrameworkElement; + + if (this.expandButton != null) + { + this.expandButton.Click -= this.OnExpandClick; + } + + this.expandButton = this.GetTemplateChild("PART_ExpandButton") as ToggleButton; + + if (this.expandButton != null) + { + this.expandButton.Click += this.OnExpandClick; + } + + if (this.dropDownButton != null) + { + this.dropDownButton.Click -= this.OnDropDownClick; + } + + this.dropDownButton = this.GetTemplateChild("PART_DropDownButton") as ToggleButton; + + if (this.dropDownButton != null) + { + this.dropDownButton.Click += this.OnDropDownClick; + } + + if (this.popup != null) + { + this.popup.Opened -= this.OnDropDownOpened; + this.popup.Closed -= this.OnDropDownClosed; + + this.popup.PreviewMouseLeftButtonUp -= this.OnPopupPreviewMouseUp; + this.popup.PreviewMouseLeftButtonDown -= this.OnPopupPreviewMouseDown; + } + + this.popup = this.GetTemplateChild("PART_Popup") as Popup; + + if (this.popup != null) + { + this.popup.Opened += this.OnDropDownOpened; + this.popup.Closed += this.OnDropDownClosed; + + this.popup.PreviewMouseLeftButtonUp += this.OnPopupPreviewMouseUp; + this.popup.PreviewMouseLeftButtonDown += this.OnPopupPreviewMouseDown; + + KeyboardNavigation.SetControlTabNavigation(this.popup, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetDirectionalNavigation(this.popup, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetTabNavigation(this.popup, KeyboardNavigationMode.Cycle); + } + + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; + } + + this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; + + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; + } + + this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; + } + + this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; + + this.groupsMenuButton?.Items.Clear(); + + this.groupsMenuButton = this.GetTemplateChild("PART_FilterDropDownButton") as DropDownButton; + + if (this.groupsMenuButton != null) + { + foreach (var currentFilter in this.Filters) + { + var item = new MenuItem + { + Header = currentFilter.Title, + Tag = currentFilter, + IsDefinitive = false + }; + + if (ReferenceEquals(currentFilter, this.SelectedFilter)) + { + item.IsChecked = true; + } + + item.Click += this.OnFilterMenuItemClick; + this.groupsMenuButton.Items.Add(item); + } + } + + this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel; + + if (this.galleryPanel != null) + { + this.galleryPanel.MinItemsInRow = this.MinItemsInRow; + this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow; + this.galleryPanel.UpdateMinAndMaxWidth(); + } + + this.snappedImage = this.GetTemplateChild("PART_FakeImage") as Image; + + this.controlPresenter = this.GetTemplateChild("PART_ContentPresenter") as ContentControl; + + this.popupControlPresenter = this.GetTemplateChild("PART_PopupContentPresenter") as ContentControl; + + this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; + + this.RunInDispatcherAsync(this.ForceContentRefreshToFixLayout, DispatcherPriority.ContextIdle); + } + + /// + /// Hack: This fixes weird layout bugs. If someone ever finds out why the layout gets messed up without this, please notify me. + /// For example #123 (https://github.com/fluentribbon/Fluent.Ribbon/issues/123) gets fixed by this hack. + /// + private void ForceContentRefreshToFixLayout() + { + if (this.controlPresenter == null + || this.galleryPanel == null) + { + return; + } + + this.controlPresenter.Content = null; + this.controlPresenter.Content = this.galleryPanel; + + this.galleryPanel.UpdateMinAndMaxWidth(); + } + + private void OnPopupPreviewMouseUp(object sender, MouseButtonEventArgs e) + { + // Ignore mouse up when mouse donw is on expand button + if (this.isButtonClicked) + { + this.isButtonClicked = false; + e.Handled = true; + } + } + + private void OnPopupPreviewMouseDown(object sender, MouseButtonEventArgs e) + { + this.isButtonClicked = false; + } + + private void OnExpandClick(object sender, RoutedEventArgs e) + { + this.isButtonClicked = true; + } + + private void OnDropDownClick(object sender, RoutedEventArgs e) + { + if (this.canOpenDropDown) + { + this.IsDropDownOpen = true; + } + } + + // Handles drop down opened + private void OnDropDownClosed(object sender, EventArgs e) + { + this.popupControlPresenter.Content = null; + this.controlPresenter.Content = this.galleryPanel; + + this.galleryPanel.IsGrouped = false; + this.galleryPanel.MinItemsInRow = this.MinItemsInRow; + this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow; + this.galleryPanel.Width = double.NaN; + this.galleryPanel.UpdateMinAndMaxWidth(); + + this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() => + { + if (this.quickAccessGallery == null + || (this.quickAccessGallery != null && this.quickAccessGallery.IsDropDownOpen == false)) + { + this.IsSnapped = false; + } + })); + + this.DropDownClosed?.Invoke(this, e); + + if (ReferenceEquals(Mouse.Captured, this)) + { + Mouse.Capture(null); + } + + this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() => + { + var selectedContainer = this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as GalleryItem; + selectedContainer?.BringIntoView(); + })); + this.dropDownButton.IsChecked = false; + this.canOpenDropDown = true; + } + + // Handles drop down closed + private void OnDropDownOpened(object sender, EventArgs e) + { + this.IsSnapped = true; + + this.controlPresenter.Content = null; + this.popupControlPresenter.Content = this.galleryPanel; + + this.galleryPanel.IsGrouped = true; + this.galleryPanel.MinItemsInRow = this.MinItemsInDropDownRow; + this.galleryPanel.MaxItemsInRow = this.MaxItemsInDropDownRow; + this.galleryPanel.Width = double.NaN; + this.galleryPanel.UpdateMinAndMaxWidth(); + + this.DropDownOpened?.Invoke(this, e); + + this.dropDownButton.IsChecked = true; + this.canOpenDropDown = false; + + Mouse.Capture(this, CaptureMode.SubTree); + + this.focusedElement = Keyboard.FocusedElement; + Debug.WriteLine("Focused element - " + this.focusedElement); + + if (this.focusedElement != null) + { + this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; + this.focusedElement.PreviewKeyDown += this.OnFocusedElementPreviewKeyDown; + } + + //if (ResizeMode != ContextMenuResizeMode.None) + { + this.scrollViewer.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height, this.MaxDropDownHeight); + + if (double.IsNaN(this.DropDownHeight) == false) + { + initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight); + } + + var initialWidth = Math.Min(RibbonControl.GetControlWorkArea(this).Height, this.MaxDropDownWidth); + + if (double.IsNaN(this.DropDownWidth) == false) + { + initialWidth = Math.Min(this.DropDownWidth, this.MaxDropDownWidth); + } + + double menuHeight = 0; + double menuWidth = 0; + + if (this.Menu != null) + { + this.Menu.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + menuHeight = this.Menu.DesiredSize.Height; + menuWidth = this.Menu.DesiredSize.Width; + } + + if (this.scrollViewer.DesiredSize.Height > initialHeight) + { + this.scrollViewer.Height = initialHeight - menuHeight; + + if (this.scrollViewer.Height < this.galleryPanel.GetItemSize().Height) + { + this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height; + } + } + + if (this.scrollViewer.DesiredSize.Width > initialWidth) + { + this.scrollViewer.Width = initialWidth - menuWidth; + + if (this.scrollViewer.Width < this.galleryPanel.GetItemSize().Width) + { + this.scrollViewer.Width = this.galleryPanel.GetItemSize().Width; + } + } + } + } + + /// + /// Handles size property changing + /// + /// Previous value + /// Current value + public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) + { + if (this.CanCollapseToButton) + { + if (current == RibbonControlSize.Large + && this.galleryPanel.MinItemsInRow > this.MinItemsInRow) + { + this.IsCollapsed = false; + } + else + { + this.IsCollapsed = true; + } + } + else + { + this.IsCollapsed = false; + } + } + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new GalleryItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is GalleryItem; + } + + /// + /// Invoked when the event is received. + /// + /// Information about the event. + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Key == Key.Escape) + { + this.IsDropDownOpen = false; + } + + base.OnKeyDown(e); + } + + private void OnFocusedElementPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Escape) + { + this.IsDropDownOpen = false; + } + } + + private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; + this.focusedElement.PreviewKeyDown -= this.OnFocusedElementPreviewKeyDown; + } + + #endregion + + #region Private Methods + + // Handles resize both drag + private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) + { + this.OnResizeVerticalDelta(sender, e); + + this.menuPanel.Width = double.NaN; + + if (double.IsNaN(this.galleryPanel.Width)) + { + this.galleryPanel.Width = this.galleryPanel.ActualWidth; + } + + this.galleryPanel.Width = Math.Max(this.layoutRoot.ActualWidth, this.galleryPanel.Width + e.HorizontalChange); + } + + // Handles resize vertical drag + private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) + { + if (double.IsNaN(this.scrollViewer.Height)) + { + this.scrollViewer.Height = this.scrollViewer.ActualHeight; + } + + this.scrollViewer.Height = Math.Max(this.layoutRoot.ActualHeight, Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); + } + + #endregion + + #region QuickAccess + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + var gallery = new InRibbonGallery(); + RibbonControl.BindQuickAccessItem(this, gallery); + RibbonControl.Bind(this, gallery, "GroupBy", GroupByProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemHeight", ItemHeightProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemWidth", ItemWidthProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ResizeMode", ResizeModeProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "MinItemsInDropDownRow", MinItemsInDropDownRowProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "MaxItemsInDropDownRow", MaxItemsInDropDownRowProperty, BindingMode.OneWay); + + RibbonControl.Bind(this, gallery, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "MaxDropDownWidth", MaxDropDownWidthProperty, BindingMode.OneWay); + RibbonControl.Bind(this, gallery, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); + + gallery.DropDownOpened += this.OnQuickAccessOpened; + + if (this.DropDownClosed != null) + { + gallery.DropDownClosed += this.DropDownClosed; + } + + if (this.DropDownOpened != null) + { + gallery.DropDownOpened += this.DropDownOpened; + } + + RibbonProperties.SetSize(gallery, RibbonControlSize.Small); + this.quickAccessGallery = gallery; + + return gallery; + } + + private object selectedItem; + private InRibbonGallery quickAccessGallery; + + private void OnQuickAccessOpened(object sender, EventArgs e) + { + for (var i = 0; i < this.Filters.Count; i++) + { + this.quickAccessGallery.Filters.Add(this.Filters[i]); + } + + this.quickAccessGallery.SelectedFilter = this.SelectedFilter; + + this.quickAccessGallery.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; + this.quickAccessGallery.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; + + this.UpdateLayout(); + this.Dispatcher.BeginInvoke(DispatcherPriority.Render, (Action)this.Freeze); + } + + private void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) + { + this.quickAccessGallery.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; + this.quickAccessGallery.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; + + this.SelectedFilter = this.quickAccessGallery.SelectedFilter; + this.quickAccessGallery.Filters.Clear(); + this.Unfreeze(); + } + + private void Freeze() + { + this.IsSnapped = true; + this.selectedItem = this.SelectedItem; + this.SelectedItem = null; + + ItemsControlHelper.MoveItemsToDifferentControl(this, this.quickAccessGallery); + + this.quickAccessGallery.SelectedItem = this.selectedItem; + this.quickAccessGallery.Menu = this.Menu; + this.Menu = null; + } + + private void Unfreeze() + { + this.selectedItem = this.quickAccessGallery.SelectedItem; + this.quickAccessGallery.SelectedItem = null; + + ItemsControlHelper.MoveItemsToDifferentControl(this.quickAccessGallery, this); + + this.SelectedItem = this.selectedItem; + this.Menu = this.quickAccessGallery.Menu; + this.quickAccessGallery.Menu = null; + + if (this.IsDropDownOpen == false) + { + if (this.controlPresenter != null) + { + this.controlPresenter.Content = null; + } + + if (this.popupControlPresenter != null) + { + this.popupControlPresenter.Content = this.galleryPanel; + } + + if (this.galleryPanel != null) + { + this.galleryPanel.IsGrouped = true; + this.galleryPanel.IsGrouped = false; + } + + if (this.popupControlPresenter != null) + { + this.popupControlPresenter.Content = null; + } + + if (this.controlPresenter != null) + { + this.controlPresenter.Content = this.galleryPanel; + } + } + + this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() => + { + if (this.IsDropDownOpen == false) + { + this.IsSnapped = false; + } + + var selectedContainer = this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as GalleryItem; + selectedContainer?.BringIntoView(); + })); + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(InRibbonGallery), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IScalableRibbonControl + + /// + /// Enlarge control size + /// + public void Enlarge() + { + if (this.IsCollapsed + && RibbonProperties.GetSize(this) == RibbonControlSize.Large) + { + this.IsCollapsed = false; + } + else if (this.galleryPanel.MinItemsInRow < this.MaxItemsInRow) + { + this.galleryPanel.MinItemsInRow++; + this.galleryPanel.MaxItemsInRow = this.galleryPanel.MinItemsInRow; + } + else + { + return; + } + + this.InvalidateMeasure(); + + this.Scaled?.Invoke(this, EventArgs.Empty); + } + + /// + /// Reduce control size + /// + public void Reduce() + { + if (this.galleryPanel.MinItemsInRow > this.MinItemsInRow) + { + this.galleryPanel.MinItemsInRow--; + this.galleryPanel.MaxItemsInRow = this.galleryPanel.MinItemsInRow; + } + else if (this.CanCollapseToButton + && this.IsCollapsed == false) + { + this.IsCollapsed = true; + } + else + { + return; + } + this.InvalidateMeasure(); + + this.Scaled?.Invoke(this, EventArgs.Empty); + } + + #endregion + + /// + /// Gets an enumerator for the logical child objects of the object. + /// + /// + /// An enumerator for the logical child objects of the object. The default is null. + /// + protected override IEnumerator LogicalChildren + { + get + { + if (this.galleryPanel != null) + { + yield return this.galleryPanel; + } + } + } + } } \ No newline at end of file diff --git a/Fluent/Controls/KeyTip.cs b/Fluent.Ribbon/Controls/KeyTip.cs similarity index 93% rename from Fluent/Controls/KeyTip.cs rename to Fluent.Ribbon/Controls/KeyTip.cs index ea1d97347..0de545b3c 100644 --- a/Fluent/Controls/KeyTip.cs +++ b/Fluent.Ribbon/Controls/KeyTip.cs @@ -1,247 +1,238 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; - -namespace Fluent -{ - /// - /// Represents KeyTip control - /// - public class KeyTip : Label - { - #region Keys Attached Property - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeysProperty = DependencyProperty.RegisterAttached( - "Keys", - typeof(string), - typeof(KeyTip), - new FrameworkPropertyMetadata(null, KeysPropertyChanged) - ); - - static void KeysPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - - } - - /// - /// Sets value of attached property Keys for the given element - /// - /// The given element - /// Value - public static void SetKeys(DependencyObject element, string value) - { - element.SetValue(KeysProperty, value); - } - - /// - /// Gets value of the attached property Keys of the given element - /// - /// The given element - [System.ComponentModel.DisplayName("Keys"), - AttachedPropertyBrowsableForChildren(IncludeDescendants = true), - System.ComponentModel.Category("KeyTips"), - System.ComponentModel.Description("Key sequence for the given element")] - public static string GetKeys(DependencyObject element) - { - return (string)element.GetValue(KeysProperty); - } - - #endregion - - #region AutoPlacement Attached Property - - /// - /// Using a DependencyProperty as the backing store for AutoPlacement. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty AutoPlacementProperty = DependencyProperty.RegisterAttached( - "AutoPlacement", - typeof(bool), - typeof(KeyTip), - new FrameworkPropertyMetadata(true) - ); - - - /// - /// Sets whether key tip placement is auto - /// or defined by alignment and margin properties - /// - /// The given element - /// Value - public static void SetAutoPlacement(DependencyObject element, bool value) - { - element.SetValue(AutoPlacementProperty, value); - } - - /// - /// Gets whether key tip placement is auto - /// or defined by alignment and margin properties - /// - /// The given element - [System.ComponentModel.DisplayName("AutoPlacement"), - AttachedPropertyBrowsableForChildren(IncludeDescendants = true), - System.ComponentModel.Category("KeyTips"), - System.ComponentModel.Description("Whether key tip placement is auto or defined by alignment and margin properties")] - public static bool GetAutoPlacement(DependencyObject element) - { - return (bool)element.GetValue(AutoPlacementProperty); - } - - #endregion - - #region HorizontalAlignment Attached Property - - /// - /// Using a DependencyProperty as the backing store for HorizontalAlignment. - /// This enables animation, styling, binding, etc... - /// - public static new readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.RegisterAttached( - "HorizontalAlignment", - typeof(HorizontalAlignment), - typeof(KeyTip), - new FrameworkPropertyMetadata(HorizontalAlignment.Center) - ); - - - /// - /// Sets Horizontal Alignment of the key tip - /// - /// The given element - /// Value - public static void SetHorizontalAlignment(DependencyObject element, HorizontalAlignment value) - { - element.SetValue(HorizontalAlignmentProperty, value); - } - - /// - /// Gets Horizontal alignment of the key tip - /// - /// The given element - [System.ComponentModel.DisplayName("HorizontalAlignment"), - AttachedPropertyBrowsableForChildren(IncludeDescendants = true), - System.ComponentModel.Category("KeyTips"), - System.ComponentModel.Description("Horizontal alignment of the key tip")] - public static HorizontalAlignment GetHorizontalAlignment(DependencyObject element) - { - return (HorizontalAlignment)element.GetValue(HorizontalAlignmentProperty); - } - - #endregion - - #region VerticalAlignment Attached Property - - /// - /// Gets vertical alignment of the key tip - /// - /// The given element - [System.ComponentModel.DisplayName("VerticalAlignment"), - AttachedPropertyBrowsableForChildren(IncludeDescendants = true), - System.ComponentModel.Category("KeyTips"), - System.ComponentModel.Description("Vertical alignment of the key tip")] - public static VerticalAlignment GetVerticalAlignment(DependencyObject element) - { - return (VerticalAlignment)element.GetValue(VerticalAlignmentProperty); - } - - /// - /// Sets vertical alignment of the key tip - /// - /// The given element - /// Value - public static void SetVerticalAlignment(DependencyObject obj, VerticalAlignment value) - { - obj.SetValue(VerticalAlignmentProperty, value); - } - - /// - /// Using a DependencyProperty as the backing store for VerticalAlignment. - /// This enables animation, styling, binding, etc... - /// - public static new readonly DependencyProperty VerticalAlignmentProperty = - DependencyProperty.RegisterAttached("VerticalAlignment", - typeof(VerticalAlignment), typeof(KeyTip), - new UIPropertyMetadata(VerticalAlignment.Center)); - - #endregion - - #region Margin Attached Property - - /// - /// Gets margin of the key tip - /// - /// The key tip - /// Margin - [System.ComponentModel.DisplayName("Margin"), - AttachedPropertyBrowsableForChildren(IncludeDescendants = true), - System.ComponentModel.Category("KeyTips"), - System.ComponentModel.Description("Margin of the key tip")] - public static Thickness GetMargin(DependencyObject obj) - { - return (Thickness)obj.GetValue(MarginProperty); - } - - /// - /// Sets margin of the key tip - /// - /// The key tip - /// Value - public static void SetMargin(DependencyObject obj, Thickness value) - { - obj.SetValue(MarginProperty, value); - } - - /// - /// Using a DependencyProperty as the backing store for Margin. - /// This enables animation, styling, binding, etc... - /// - public static new readonly DependencyProperty MarginProperty = - DependencyProperty.RegisterAttached("Margin", typeof(Thickness), typeof(KeyTip), new UIPropertyMetadata(new Thickness())); - - #endregion - - #region Initialization - - // Static constructor - [SuppressMessage("Microsoft.Performance", "CA1810")] - static KeyTip() - { - // Override metadata to allow slyling - //StyleProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - DefaultStyleKeyProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(typeof(KeyTip))); - StyleProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(KeyTip)); - } - - return basevalue; - } - - /// - /// Default constrctor - /// - public KeyTip() - { - } - - #endregion - } -} +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls; + +namespace Fluent +{ + /// + /// Represents KeyTip control + /// + public class KeyTip : Label + { + #region Keys Attached Property + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeysProperty = DependencyProperty.RegisterAttached( + "Keys", + typeof(string), + typeof(KeyTip), + new FrameworkPropertyMetadata(null, KeysPropertyChanged) + ); + + static void KeysPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + + } + + /// + /// Sets value of attached property Keys for the given element + /// + /// The given element + /// Value + public static void SetKeys(DependencyObject element, string value) + { + element.SetValue(KeysProperty, value); + } + + /// + /// Gets value of the attached property Keys of the given element + /// + /// The given element + [System.ComponentModel.DisplayName("Keys"), + AttachedPropertyBrowsableForChildren(IncludeDescendants = true), + System.ComponentModel.Category("KeyTips"), + System.ComponentModel.Description("Key sequence for the given element")] + public static string GetKeys(DependencyObject element) + { + return (string)element.GetValue(KeysProperty); + } + + #endregion + + #region AutoPlacement Attached Property + + /// + /// Using a DependencyProperty as the backing store for AutoPlacement. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty AutoPlacementProperty = DependencyProperty.RegisterAttached( + "AutoPlacement", + typeof(bool), + typeof(KeyTip), + new FrameworkPropertyMetadata(true) + ); + + + /// + /// Sets whether key tip placement is auto + /// or defined by alignment and margin properties + /// + /// The given element + /// Value + public static void SetAutoPlacement(DependencyObject element, bool value) + { + element.SetValue(AutoPlacementProperty, value); + } + + /// + /// Gets whether key tip placement is auto + /// or defined by alignment and margin properties + /// + /// The given element + [System.ComponentModel.DisplayName("AutoPlacement"), + AttachedPropertyBrowsableForChildren(IncludeDescendants = true), + System.ComponentModel.Category("KeyTips"), + System.ComponentModel.Description("Whether key tip placement is auto or defined by alignment and margin properties")] + public static bool GetAutoPlacement(DependencyObject element) + { + return (bool)element.GetValue(AutoPlacementProperty); + } + + #endregion + + #region HorizontalAlignment Attached Property + + /// + /// Using a DependencyProperty as the backing store for HorizontalAlignment. + /// This enables animation, styling, binding, etc... + /// + public static new readonly DependencyProperty HorizontalAlignmentProperty = DependencyProperty.RegisterAttached( + "HorizontalAlignment", + typeof(HorizontalAlignment), + typeof(KeyTip), + new FrameworkPropertyMetadata(HorizontalAlignment.Center) + ); + + + /// + /// Sets Horizontal Alignment of the key tip + /// + /// The given element + /// Value + public static void SetHorizontalAlignment(DependencyObject element, HorizontalAlignment value) + { + element.SetValue(HorizontalAlignmentProperty, value); + } + + /// + /// Gets Horizontal alignment of the key tip + /// + /// The given element + [System.ComponentModel.DisplayName("HorizontalAlignment"), + AttachedPropertyBrowsableForChildren(IncludeDescendants = true), + System.ComponentModel.Category("KeyTips"), + System.ComponentModel.Description("Horizontal alignment of the key tip")] + public static HorizontalAlignment GetHorizontalAlignment(DependencyObject element) + { + return (HorizontalAlignment)element.GetValue(HorizontalAlignmentProperty); + } + + #endregion + + #region VerticalAlignment Attached Property + + /// + /// Gets vertical alignment of the key tip + /// + /// The given element + [System.ComponentModel.DisplayName("VerticalAlignment"), + AttachedPropertyBrowsableForChildren(IncludeDescendants = true), + System.ComponentModel.Category("KeyTips"), + System.ComponentModel.Description("Vertical alignment of the key tip")] + public static VerticalAlignment GetVerticalAlignment(DependencyObject element) + { + return (VerticalAlignment)element.GetValue(VerticalAlignmentProperty); + } + + /// + /// Sets vertical alignment of the key tip + /// + /// The given element + /// Value + public static void SetVerticalAlignment(DependencyObject obj, VerticalAlignment value) + { + obj.SetValue(VerticalAlignmentProperty, value); + } + + /// + /// Using a DependencyProperty as the backing store for VerticalAlignment. + /// This enables animation, styling, binding, etc... + /// + public static new readonly DependencyProperty VerticalAlignmentProperty = + DependencyProperty.RegisterAttached("VerticalAlignment", + typeof(VerticalAlignment), typeof(KeyTip), + new UIPropertyMetadata(VerticalAlignment.Center)); + + #endregion + + #region Margin Attached Property + + /// + /// Gets margin of the key tip + /// + /// The key tip + /// Margin + [System.ComponentModel.DisplayName("Margin"), + AttachedPropertyBrowsableForChildren(IncludeDescendants = true), + System.ComponentModel.Category("KeyTips"), + System.ComponentModel.Description("Margin of the key tip")] + public static Thickness GetMargin(DependencyObject obj) + { + return (Thickness)obj.GetValue(MarginProperty); + } + + /// + /// Sets margin of the key tip + /// + /// The key tip + /// Value + public static void SetMargin(DependencyObject obj, Thickness value) + { + obj.SetValue(MarginProperty, value); + } + + /// + /// Using a DependencyProperty as the backing store for Margin. + /// This enables animation, styling, binding, etc... + /// + public static new readonly DependencyProperty MarginProperty = + DependencyProperty.RegisterAttached("Margin", typeof(Thickness), typeof(KeyTip), new UIPropertyMetadata(new Thickness())); + + #endregion + + #region Initialization + + // Static constructor + [SuppressMessage("Microsoft.Performance", "CA1810")] + static KeyTip() + { + // Override metadata to allow slyling + //StyleProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + DefaultStyleKeyProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(typeof(KeyTip))); + StyleProperty.OverrideMetadata(typeof(KeyTip), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(KeyTip)); + } + + return basevalue; + } + + /// + /// Default constrctor + /// + public KeyTip() + { + } + + #endregion + } +} diff --git a/Fluent/Controls/MenuItem.cs b/Fluent.Ribbon/Controls/MenuItem.cs similarity index 96% rename from Fluent/Controls/MenuItem.cs rename to Fluent.Ribbon/Controls/MenuItem.cs index ec653addb..13a791150 100644 --- a/Fluent/Controls/MenuItem.cs +++ b/Fluent.Ribbon/Controls/MenuItem.cs @@ -1,786 +1,777 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; - -namespace Fluent -{ - using Fluent.Internal; - - /// - /// Represents menu item - /// - [ContentProperty("Items")] - public class MenuItem : System.Windows.Controls.MenuItem, IQuickAccessItemProvider, IRibbonControl - { - #region Fields - - private Popup popup; - - // Thumb to resize in both directions - Thumb resizeBothThumb; - // Thumb to resize vertical - Thumb resizeVerticalThumb; - - private Panel menuPanel; - - private ScrollViewer scrollViewer; - - #endregion - - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(MenuItem)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(MenuItem)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(MenuItem)); - - #endregion - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup - { - get { return this.popup; } - } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - #region Description - - /// - /// Useless property only used in secon level application menu items - /// - public string Description - { - get { return (string)this.GetValue(DescriptionProperty); } - set { this.SetValue(DescriptionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Description. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DescriptionProperty = - DependencyProperty.Register("Description", typeof(string), typeof(MenuItem), new UIPropertyMetadata("")); - - - #endregion - - #region IsDropDownOpen - - /// - /// Gets or sets whether popup is opened - /// - public bool IsDropDownOpen - { - get { return this.IsSubmenuOpen; } - set { this.IsSubmenuOpen = value; } - } - - #endregion - - #region IsDefinitive - - /// - /// Gets or sets whether ribbon control click must close backstage - /// - public bool IsDefinitive - { - get { return (bool)this.GetValue(IsDefinitiveProperty); } - set { this.SetValue(IsDefinitiveProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDefinitiveProperty = - DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(MenuItem), new UIPropertyMetadata(true)); - - #endregion - - #region ResizeMode - - /// - /// Gets or sets context menu resize mode - /// - public ContextMenuResizeMode ResizeMode - { - get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } - set { this.SetValue(ResizeModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeMode. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeModeProperty = - DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), - typeof(MenuItem), new UIPropertyMetadata(ContextMenuResizeMode.None)); - - - #endregion - - #region MaxDropDownHeight - - /// - /// Get or sets max height of drop down popup - /// - public double MaxDropDownHeight - { - get { return (double)this.GetValue(MaxDropDownHeightProperty); } - set { this.SetValue(MaxDropDownHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxDropDownHeightProperty = - DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(MenuItem), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); - - #endregion - - #region IsSplited - - /// - /// Gets or sets a value indicating whether menu item is splited - /// - public bool IsSplited - { - get { return (bool)this.GetValue(IsSplitedProperty); } - set { this.SetValue(IsSplitedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsSplited. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsSplitedProperty = - DependencyProperty.Register("IsSplited", typeof(bool), typeof(MenuItem), new UIPropertyMetadata(false)); - - #endregion - - #region GroupName - - /// - /// Gets or sets the name of the group that the toggle button belongs to. - /// Use the GroupName property to specify a grouping of toggle buttons to - /// create a mutually exclusive set of controls. You can use the GroupName - /// property when only one selection is possible from a list of available - /// options. When this property is set, only one ToggleButton in the specified - /// group can be selected at a time. - /// - public string GroupName - { - get { return (string)this.GetValue(GroupNameProperty); } - set { this.SetValue(GroupNameProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupName. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupNameProperty = - DependencyProperty.Register("GroupName", typeof(string), typeof(MenuItem), - new UIPropertyMetadata(null, OnGroupNameChanged)); - - // Group name changed - static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - MenuItem toggleButton = (MenuItem)d; - string currentGroupName = (string)e.NewValue; - string previousGroupName = (string)e.OldValue; - - if (previousGroupName != null) RemoveFromGroup(previousGroupName, toggleButton); - if (currentGroupName != null) AddToGroup(currentGroupName, toggleButton); - } - - #region Grouped Items Methods - - // Grouped buttons (thread id / group name / weak ref to a control) - static readonly Dictionary>> groupedButtons = - new Dictionary>>(); - - // Remove from group - static void RemoveFromGroup(string groupName, MenuItem button) - { - List buttons = null; - int threadId = Thread.CurrentThread.ManagedThreadId; - if (!groupedButtons.ContainsKey(threadId)) return; - if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) return; - - buttons.RemoveAt(buttons.FindIndex(x => (x.IsAlive && ((MenuItem)x.Target) == button))); - } - - // Remove from group - static void AddToGroup(string groupName, MenuItem button) - { - int threadId = Thread.CurrentThread.ManagedThreadId; - if (!groupedButtons.ContainsKey(threadId)) groupedButtons.Add(threadId, new Dictionary>()); - - List buttons = null; - if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) - { - buttons = new List(); - groupedButtons[threadId].Add(groupName, buttons); - } - - buttons.Add(new WeakReference(button)); - } - - // Gets all buttons in the given group - static IEnumerable GetItemsInGroup(string groupName) - { - int threadId = Thread.CurrentThread.ManagedThreadId; - if (!groupedButtons.ContainsKey(threadId)) return new List(); - - List buttons = null; - if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) return new List(); - return buttons.Where(x => x.IsAlive).Select(x => (MenuItem)x.Target); - } - - #endregion - - #region IsChecked - - // Coerce IsChecked - static object CoerceIsChecked(DependencyObject d, object basevalue) - { - MenuItem toggleButton = (MenuItem)d; - if (toggleButton.GroupName == null) return basevalue; - - bool baseIsChecked = (bool)basevalue; - if (!baseIsChecked) - { - // We can not allow that there are no one button checked - foreach (MenuItem item in GetItemsInGroup(toggleButton.GroupName)) - { - // It's Ok, atleast one checked button exists - if (item.IsChecked) return false; - } - - // This button can not be unchecked - return true; - } - return basevalue; - } - - // Handles isChecked changed - private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - bool newValue = (bool)e.NewValue; - bool oldValue = (bool)e.OldValue; - MenuItem button = (MenuItem)d; - - // Uncheck other toggle buttons - if (newValue && button.GroupName != null) - { - foreach (MenuItem item in GetItemsInGroup(button.GroupName)) - if (item != button) item.IsChecked = false; - } - } - - #endregion - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when context menu is opened - /// - public event EventHandler DropDownOpened; - - /// - /// Occurs when context menu is closed - /// - public event EventHandler DropDownClosed; - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static MenuItem() - { - Type type = typeof(MenuItem); - ToolTipService.Attach(type); - //PopupService.Attach(type); - ContextMenuService.Attach(type); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - IsCheckedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, OnIsCheckedChanged, CoerceIsChecked)); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(MenuItem)); - } - - return basevalue; - } - - /// - /// Default Constructor - /// - public MenuItem() - { - ContextMenuService.Coerce(this); - - this.MouseWheel += this.OnMenuItemMouseWheel; - } - - // Fix to raise MouseWhele event - private void OnMenuItemMouseWheel(object sender, MouseWheelEventArgs e) - { - if (((MenuItem)sender).Parent as ListBox != null) - { - ((ListBox)((MenuItem)sender).Parent).RaiseEvent(e); - } - } - - #endregion - - #region QuickAccess - - /// - /// Gets control which represents shortcut item. - /// This item MUST be synchronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public FrameworkElement CreateQuickAccessItem() - { - if (this.HasItems) - { - if (this.IsSplited) - { - SplitButton button = new SplitButton(); - RibbonControl.BindQuickAccessItem(this, button); - RibbonControl.Bind(this, button, "ResizeMode", ResizeModeProperty, BindingMode.Default); - RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); - RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - button.DropDownOpened += this.OnQuickAccessOpened; - return button; - } - else - { - DropDownButton button = new DropDownButton(); - RibbonControl.BindQuickAccessItem(this, button); - RibbonControl.Bind(this, button, "ResizeMode", ResizeModeProperty, BindingMode.Default); - RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); - RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - button.DropDownOpened += this.OnQuickAccessOpened; - return button; - } - } - else - { - Button button = new Button(); - RibbonControl.BindQuickAccessItem(this, button); - return button; - } - } - - /// - /// Handles quick access button drop down menu opened - /// - /// - /// - protected void OnQuickAccessOpened(object sender, EventArgs e) - { - var buttonInQuickAccess = (DropDownButton)sender; - - buttonInQuickAccess.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; - buttonInQuickAccess.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; - - ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); - } - - /// - /// Handles quick access button drop down menu closed - /// - /// - /// - protected void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) - { - var buttonInQuickAccess = (DropDownButton)sender; - - buttonInQuickAccess.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; - buttonInQuickAccess.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; - - ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(MenuItem)); - - #endregion - - #region Public - - /// - /// Handles key tip pressed - /// - public virtual void OnKeyTipPressed() - { - if (!this.HasItems) - { - this.OnClick(); - } - else - { - Keyboard.Focus(this); - this.IsDropDownOpen = true; - } - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - this.IsDropDownOpen = false; - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new MenuItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return (item is FrameworkElement); - } - - /// - /// Called when the left mouse button is released. - /// - /// The event data for the event. - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) - { - if (e.ClickCount == 1) - { - if (this.IsSplited) - { - Border buttonBorder = this.GetTemplateChild("PART_ButtonBorder") as Border; - if ((buttonBorder != null) && (PopupService.IsMousePhysicallyOver(buttonBorder))) - { - /*if (Command != null) - { - RoutedCommand command = Command as RoutedCommand; - if (command != null) command.Execute(CommandParameter, CommandTarget); - else Command.Execute(CommandParameter); - }*/ - this.OnClick(); - } - } - } - base.OnMouseLeftButtonUp(e); - } - - /// - /// Called when a is clicked. - /// - protected override void OnClick() - { - // Close popup on click - if (this.IsDefinitive - && (!this.HasItems || this.IsSplited)) - { - PopupService.RaiseDismissPopupEventAsync(this, DismissPopupMode.Always); - } - - base.OnClick(); - } - - /// - /// Called when the template's tree is generated. - /// - public override void OnApplyTemplate() - { - if (this.popup != null) - { - this.popup.Opened -= this.OnDropDownOpened; - this.popup.Closed -= this.OnDropDownClosed; - } - - this.popup = this.GetTemplateChild("PART_Popup") as Popup; - - if (this.popup != null) - { - this.popup.Opened += this.OnDropDownOpened; - this.popup.Closed += this.OnDropDownClosed; - - KeyboardNavigation.SetControlTabNavigation(this.popup, KeyboardNavigationMode.Cycle); - KeyboardNavigation.SetDirectionalNavigation(this.popup, KeyboardNavigationMode.Cycle); - KeyboardNavigation.SetTabNavigation(this.popup, KeyboardNavigationMode.Cycle); - } - - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; - } - this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; - } - this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; - } - this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; - this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; - } - - /// - /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The that contains the event data. - protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - Debug.WriteLine("MenuItem focus lost - " + this); - //base.OnPreviewLostKeyboardFocus(e); - //e.Handled = true; - } - - /// - /// Responds to the event. - /// - /// The event data for the event. - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.Key == Key.Escape) - { - if (this.IsSubmenuOpen) - this.IsSubmenuOpen = false; - else - { - DependencyObject parent = this.FindParentDropDownOrMenuItem(); - if (parent != null) - { - IDropDownControl dropDown = parent as IDropDownControl; - if (dropDown != null) dropDown.IsDropDownOpen = false; - else (parent as System.Windows.Controls.MenuItem).IsSubmenuOpen = false; - } - } - e.Handled = true; - } - else base.OnKeyDown(e); - } - - private DependencyObject FindParentDropDownOrMenuItem() - { - DependencyObject parent = this.Parent; - while (parent != null) - { - IDropDownControl dropDown = parent as IDropDownControl; - if (dropDown != null) return parent; - System.Windows.Controls.MenuItem menuItem = parent as System.Windows.Controls.MenuItem; - if (menuItem != null) return parent; - parent = LogicalTreeHelper.GetParent(parent); - } - return null; - } - - #endregion - - #region Methods - - // Handles resize both drag - private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) - { - if (this.scrollViewer != null) - { - this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; - } - - if (this.menuPanel != null) - { - if (double.IsNaN(this.menuPanel.Width)) - { - this.menuPanel.Width = this.menuPanel.ActualWidth; - } - - if (double.IsNaN(this.menuPanel.Height)) - { - this.menuPanel.Height = this.menuPanel.ActualHeight; - } - - this.menuPanel.Width = Math.Max(this.menuPanel.MinWidth, this.menuPanel.Width + e.HorizontalChange); - this.menuPanel.Height = Math.Min(Math.Max(this.menuPanel.MinHeight, this.menuPanel.Height + e.VerticalChange), this.MaxDropDownHeight); - } - } - - // Handles resize vertical drag - private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) - { - if (this.scrollViewer != null) - { - this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; - } - - if (this.menuPanel != null) - { - if (double.IsNaN(this.menuPanel.Height)) - { - this.menuPanel.Height = this.menuPanel.ActualHeight; - } - - this.menuPanel.Height = Math.Min(Math.Max(this.menuPanel.MinHeight, this.menuPanel.Height + e.VerticalChange), this.MaxDropDownHeight); - } - } - - // Handles drop down opened - private void OnDropDownClosed(object sender, EventArgs e) - { - if (this.DropDownClosed != null) - { - this.DropDownClosed(this, e); - } - //if (Mouse.Captured == this) Mouse.Capture(null); - } - - // Handles drop down closed - private void OnDropDownOpened(object sender, EventArgs e) - { - if (this.scrollViewer != null - && - this.ResizeMode != ContextMenuResizeMode.None) - { - this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled; - } - - if (this.menuPanel != null) - { - this.menuPanel.Width = double.NaN; - this.menuPanel.Height = double.NaN; - } - - if (this.DropDownOpened != null) - { - this.DropDownOpened(this, e); - } - //Mouse.Capture(this, CaptureMode.SubTree); - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Markup; + +namespace Fluent +{ + using Fluent.Internal; + + /// + /// Represents menu item + /// + [ContentProperty("Items")] + public class MenuItem : System.Windows.Controls.MenuItem, IQuickAccessItemProvider, IRibbonControl + { + #region Fields + + private Popup popup; + + // Thumb to resize in both directions + Thumb resizeBothThumb; + // Thumb to resize vertical + Thumb resizeVerticalThumb; + + private Panel menuPanel; + + private ScrollViewer scrollViewer; + + #endregion + + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(MenuItem)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(MenuItem)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(MenuItem)); + + #endregion + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup + { + get { return this.popup; } + } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + #region Description + + /// + /// Useless property only used in secon level application menu items + /// + public string Description + { + get { return (string)this.GetValue(DescriptionProperty); } + set { this.SetValue(DescriptionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Description. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DescriptionProperty = + DependencyProperty.Register("Description", typeof(string), typeof(MenuItem), new UIPropertyMetadata("")); + + + #endregion + + #region IsDropDownOpen + + /// + /// Gets or sets whether popup is opened + /// + public bool IsDropDownOpen + { + get { return this.IsSubmenuOpen; } + set { this.IsSubmenuOpen = value; } + } + + #endregion + + #region IsDefinitive + + /// + /// Gets or sets whether ribbon control click must close backstage + /// + public bool IsDefinitive + { + get { return (bool)this.GetValue(IsDefinitiveProperty); } + set { this.SetValue(IsDefinitiveProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDefinitiveProperty = + DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(MenuItem), new UIPropertyMetadata(true)); + + #endregion + + #region ResizeMode + + /// + /// Gets or sets context menu resize mode + /// + public ContextMenuResizeMode ResizeMode + { + get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } + set { this.SetValue(ResizeModeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeMode. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeModeProperty = + DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), + typeof(MenuItem), new UIPropertyMetadata(ContextMenuResizeMode.None)); + + + #endregion + + #region MaxDropDownHeight + + /// + /// Get or sets max height of drop down popup + /// + public double MaxDropDownHeight + { + get { return (double)this.GetValue(MaxDropDownHeightProperty); } + set { this.SetValue(MaxDropDownHeightProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxDropDownHeight. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxDropDownHeightProperty = + DependencyProperty.Register("MaxDropDownHeight", typeof(double), typeof(MenuItem), new UIPropertyMetadata(SystemParameters.PrimaryScreenHeight / 3.0)); + + #endregion + + #region IsSplited + + /// + /// Gets or sets a value indicating whether menu item is splited + /// + public bool IsSplited + { + get { return (bool)this.GetValue(IsSplitedProperty); } + set { this.SetValue(IsSplitedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsSplited. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsSplitedProperty = + DependencyProperty.Register("IsSplited", typeof(bool), typeof(MenuItem), new UIPropertyMetadata(false)); + + #endregion + + #region GroupName + + /// + /// Gets or sets the name of the group that the toggle button belongs to. + /// Use the GroupName property to specify a grouping of toggle buttons to + /// create a mutually exclusive set of controls. You can use the GroupName + /// property when only one selection is possible from a list of available + /// options. When this property is set, only one ToggleButton in the specified + /// group can be selected at a time. + /// + public string GroupName + { + get { return (string)this.GetValue(GroupNameProperty); } + set { this.SetValue(GroupNameProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupName. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupNameProperty = + DependencyProperty.Register("GroupName", typeof(string), typeof(MenuItem), + new UIPropertyMetadata(null, OnGroupNameChanged)); + + // Group name changed + static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + MenuItem toggleButton = (MenuItem)d; + string currentGroupName = (string)e.NewValue; + string previousGroupName = (string)e.OldValue; + + if (previousGroupName != null) RemoveFromGroup(previousGroupName, toggleButton); + if (currentGroupName != null) AddToGroup(currentGroupName, toggleButton); + } + + #region Grouped Items Methods + + // Grouped buttons (thread id / group name / weak ref to a control) + static readonly Dictionary>> groupedButtons = + new Dictionary>>(); + + // Remove from group + static void RemoveFromGroup(string groupName, MenuItem button) + { + List buttons = null; + int threadId = Thread.CurrentThread.ManagedThreadId; + if (!groupedButtons.ContainsKey(threadId)) return; + if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) return; + + buttons.RemoveAt(buttons.FindIndex(x => (x.IsAlive && ((MenuItem)x.Target) == button))); + } + + // Remove from group + static void AddToGroup(string groupName, MenuItem button) + { + int threadId = Thread.CurrentThread.ManagedThreadId; + if (!groupedButtons.ContainsKey(threadId)) groupedButtons.Add(threadId, new Dictionary>()); + + List buttons = null; + if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) + { + buttons = new List(); + groupedButtons[threadId].Add(groupName, buttons); + } + + buttons.Add(new WeakReference(button)); + } + + // Gets all buttons in the given group + static IEnumerable GetItemsInGroup(string groupName) + { + int threadId = Thread.CurrentThread.ManagedThreadId; + if (!groupedButtons.ContainsKey(threadId)) return new List(); + + List buttons = null; + if (!groupedButtons[threadId].TryGetValue(groupName, out buttons)) return new List(); + return buttons.Where(x => x.IsAlive).Select(x => (MenuItem)x.Target); + } + + #endregion + + #region IsChecked + + // Coerce IsChecked + static object CoerceIsChecked(DependencyObject d, object basevalue) + { + MenuItem toggleButton = (MenuItem)d; + if (toggleButton.GroupName == null) return basevalue; + + bool baseIsChecked = (bool)basevalue; + if (!baseIsChecked) + { + // We can not allow that there are no one button checked + foreach (MenuItem item in GetItemsInGroup(toggleButton.GroupName)) + { + // It's Ok, atleast one checked button exists + if (item.IsChecked) return false; + } + + // This button can not be unchecked + return true; + } + return basevalue; + } + + // Handles isChecked changed + private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + bool newValue = (bool)e.NewValue; + bool oldValue = (bool)e.OldValue; + MenuItem button = (MenuItem)d; + + // Uncheck other toggle buttons + if (newValue && button.GroupName != null) + { + foreach (MenuItem item in GetItemsInGroup(button.GroupName)) + if (item != button) item.IsChecked = false; + } + } + + #endregion + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when context menu is opened + /// + public event EventHandler DropDownOpened; + + /// + /// Occurs when context menu is closed + /// + public event EventHandler DropDownClosed; + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static MenuItem() + { + Type type = typeof(MenuItem); + ToolTipService.Attach(type); + //PopupService.Attach(type); + ContextMenuService.Attach(type); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + IsCheckedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, OnIsCheckedChanged, CoerceIsChecked)); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(MenuItem)); + } + + return basevalue; + } + + /// + /// Default Constructor + /// + public MenuItem() + { + ContextMenuService.Coerce(this); + + this.MouseWheel += this.OnMenuItemMouseWheel; + } + + // Fix to raise MouseWhele event + private void OnMenuItemMouseWheel(object sender, MouseWheelEventArgs e) + { + if (((MenuItem)sender).Parent as ListBox != null) + { + ((ListBox)((MenuItem)sender).Parent).RaiseEvent(e); + } + } + + #endregion + + #region QuickAccess + + /// + /// Gets control which represents shortcut item. + /// This item MUST be synchronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public FrameworkElement CreateQuickAccessItem() + { + if (this.HasItems) + { + if (this.IsSplited) + { + SplitButton button = new SplitButton(); + RibbonControl.BindQuickAccessItem(this, button); + RibbonControl.Bind(this, button, "ResizeMode", ResizeModeProperty, BindingMode.Default); + RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); + RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + button.DropDownOpened += this.OnQuickAccessOpened; + return button; + } + else + { + DropDownButton button = new DropDownButton(); + RibbonControl.BindQuickAccessItem(this, button); + RibbonControl.Bind(this, button, "ResizeMode", ResizeModeProperty, BindingMode.Default); + RibbonControl.Bind(this, button, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); + RibbonControl.Bind(this, button, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, button, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + button.DropDownOpened += this.OnQuickAccessOpened; + return button; + } + } + else + { + Button button = new Button(); + RibbonControl.BindQuickAccessItem(this, button); + return button; + } + } + + /// + /// Handles quick access button drop down menu opened + /// + /// + /// + protected void OnQuickAccessOpened(object sender, EventArgs e) + { + var buttonInQuickAccess = (DropDownButton)sender; + + buttonInQuickAccess.DropDownClosed += this.OnQuickAccessMenuClosedOrUnloaded; + buttonInQuickAccess.Unloaded += this.OnQuickAccessMenuClosedOrUnloaded; + + ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); + } + + /// + /// Handles quick access button drop down menu closed + /// + /// + /// + protected void OnQuickAccessMenuClosedOrUnloaded(object sender, EventArgs e) + { + var buttonInQuickAccess = (DropDownButton)sender; + + buttonInQuickAccess.DropDownClosed -= this.OnQuickAccessMenuClosedOrUnloaded; + buttonInQuickAccess.Unloaded -= this.OnQuickAccessMenuClosedOrUnloaded; + + ItemsControlHelper.MoveItemsToDifferentControl(buttonInQuickAccess, this); + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(MenuItem)); + + #endregion + + #region Public + + /// + /// Handles key tip pressed + /// + public virtual void OnKeyTipPressed() + { + if (!this.HasItems) + { + this.OnClick(); + } + else + { + Keyboard.Focus(this); + this.IsDropDownOpen = true; + } + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + this.IsDropDownOpen = false; + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new MenuItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return (item is FrameworkElement); + } + + /// + /// Called when the left mouse button is released. + /// + /// The event data for the event. + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + if (e.ClickCount == 1) + { + if (this.IsSplited) + { + Border buttonBorder = this.GetTemplateChild("PART_ButtonBorder") as Border; + if ((buttonBorder != null) && (PopupService.IsMousePhysicallyOver(buttonBorder))) + { + /*if (Command != null) + { + RoutedCommand command = Command as RoutedCommand; + if (command != null) command.Execute(CommandParameter, CommandTarget); + else Command.Execute(CommandParameter); + }*/ + this.OnClick(); + } + } + } + base.OnMouseLeftButtonUp(e); + } + + /// + /// Called when a is clicked. + /// + protected override void OnClick() + { + // Close popup on click + if (this.IsDefinitive + && (!this.HasItems || this.IsSplited)) + { + PopupService.RaiseDismissPopupEventAsync(this, DismissPopupMode.Always); + } + + base.OnClick(); + } + + /// + /// Called when the template's tree is generated. + /// + public override void OnApplyTemplate() + { + if (this.popup != null) + { + this.popup.Opened -= this.OnDropDownOpened; + this.popup.Closed -= this.OnDropDownClosed; + } + + this.popup = this.GetTemplateChild("PART_Popup") as Popup; + + if (this.popup != null) + { + this.popup.Opened += this.OnDropDownOpened; + this.popup.Closed += this.OnDropDownClosed; + + KeyboardNavigation.SetControlTabNavigation(this.popup, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetDirectionalNavigation(this.popup, KeyboardNavigationMode.Cycle); + KeyboardNavigation.SetTabNavigation(this.popup, KeyboardNavigationMode.Cycle); + } + + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; + } + this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; + if (this.resizeVerticalThumb != null) + { + this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; + } + + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; + } + this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; + if (this.resizeBothThumb != null) + { + this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; + } + this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; + this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; + } + + /// + /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + Debug.WriteLine("MenuItem focus lost - " + this); + //base.OnPreviewLostKeyboardFocus(e); + //e.Handled = true; + } + + /// + /// Responds to the event. + /// + /// The event data for the event. + protected override void OnKeyDown(KeyEventArgs e) + { + if (e.Key == Key.Escape) + { + if (this.IsSubmenuOpen) + this.IsSubmenuOpen = false; + else + { + DependencyObject parent = this.FindParentDropDownOrMenuItem(); + if (parent != null) + { + IDropDownControl dropDown = parent as IDropDownControl; + if (dropDown != null) dropDown.IsDropDownOpen = false; + else (parent as System.Windows.Controls.MenuItem).IsSubmenuOpen = false; + } + } + e.Handled = true; + } + else base.OnKeyDown(e); + } + + private DependencyObject FindParentDropDownOrMenuItem() + { + DependencyObject parent = this.Parent; + while (parent != null) + { + IDropDownControl dropDown = parent as IDropDownControl; + if (dropDown != null) return parent; + System.Windows.Controls.MenuItem menuItem = parent as System.Windows.Controls.MenuItem; + if (menuItem != null) return parent; + parent = LogicalTreeHelper.GetParent(parent); + } + return null; + } + + #endregion + + #region Methods + + // Handles resize both drag + private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) + { + if (this.scrollViewer != null) + { + this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + } + + if (this.menuPanel != null) + { + if (double.IsNaN(this.menuPanel.Width)) + { + this.menuPanel.Width = this.menuPanel.ActualWidth; + } + + if (double.IsNaN(this.menuPanel.Height)) + { + this.menuPanel.Height = this.menuPanel.ActualHeight; + } + + this.menuPanel.Width = Math.Max(this.menuPanel.MinWidth, this.menuPanel.Width + e.HorizontalChange); + this.menuPanel.Height = Math.Min(Math.Max(this.menuPanel.MinHeight, this.menuPanel.Height + e.VerticalChange), this.MaxDropDownHeight); + } + } + + // Handles resize vertical drag + private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) + { + if (this.scrollViewer != null) + { + this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto; + } + + if (this.menuPanel != null) + { + if (double.IsNaN(this.menuPanel.Height)) + { + this.menuPanel.Height = this.menuPanel.ActualHeight; + } + + this.menuPanel.Height = Math.Min(Math.Max(this.menuPanel.MinHeight, this.menuPanel.Height + e.VerticalChange), this.MaxDropDownHeight); + } + } + + // Handles drop down opened + private void OnDropDownClosed(object sender, EventArgs e) + { + if (this.DropDownClosed != null) + { + this.DropDownClosed(this, e); + } + //if (Mouse.Captured == this) Mouse.Capture(null); + } + + // Handles drop down closed + private void OnDropDownOpened(object sender, EventArgs e) + { + if (this.scrollViewer != null + && + this.ResizeMode != ContextMenuResizeMode.None) + { + this.scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled; + } + + if (this.menuPanel != null) + { + this.menuPanel.Width = double.NaN; + this.menuPanel.Height = double.NaN; + } + + if (this.DropDownOpened != null) + { + this.DropDownOpened(this, e); + } + //Mouse.Capture(this, CaptureMode.SubTree); + } + + #endregion + } +} diff --git a/Fluent/Controls/QuickAccessMenuItem.cs b/Fluent.Ribbon/Controls/QuickAccessMenuItem.cs similarity index 93% rename from Fluent/Controls/QuickAccessMenuItem.cs rename to Fluent.Ribbon/Controls/QuickAccessMenuItem.cs index 87860d3a8..3b2f7c66b 100644 --- a/Fluent/Controls/QuickAccessMenuItem.cs +++ b/Fluent.Ribbon/Controls/QuickAccessMenuItem.cs @@ -1,296 +1,287 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Data; -using System.Windows.Markup; -using System.Windows.Media; -using System.Windows.Controls; - -namespace Fluent -{ - /// - /// This interface must be implemented for controls - /// which are intended to insert to quick access toolbar - /// - public interface IQuickAccessItemProvider - { - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - FrameworkElement CreateQuickAccessItem(); - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - bool CanAddToQuickAccessToolBar { get; set; } - } - - /// - /// Peresents quick access shortcut to another control - /// - [ContentProperty("Target")] - public class QuickAccessMenuItem : MenuItem - { - #region Fields - - internal Ribbon Ribbon; - - #endregion - - #region Initialization - - [SuppressMessage("Microsoft.Performance", "CA1810")] - static QuickAccessMenuItem() - { - IsCheckableProperty.AddOwner(typeof(QuickAccessMenuItem), new FrameworkPropertyMetadata(true)); - } - - /// - /// Default constructor - /// - public QuickAccessMenuItem() - { - this.Checked += this.OnChecked; - this.Unchecked += this.OnUnchecked; - this.Loaded += this.OnFirstLoaded; - this.Loaded += this.OnItemLoaded; - } - - #endregion - - #region Target Property - - /// - /// Gets or sets shortcut to the target control - /// - public Control Target - { - get { return (Control)this.GetValue(TargetProperty); } - set { this.SetValue(TargetProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for shortcut. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TargetProperty = - DependencyProperty.Register("Target", typeof(Control), typeof(QuickAccessMenuItem), new UIPropertyMetadata(null,OnTargetChanged)); - - private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var quickAccessMenuItem = (QuickAccessMenuItem)d; - var ribbonControl = e.NewValue as IRibbonControl; - - if (quickAccessMenuItem.Header == null - && ribbonControl != null) - { - // Set Default Text Value - RibbonControl.Bind(ribbonControl, quickAccessMenuItem, "Header", HeaderProperty, BindingMode.OneWay); - } - - if (ribbonControl != null) - { - var parent = LogicalTreeHelper.GetParent((DependencyObject)ribbonControl); - if (parent == null) - { - quickAccessMenuItem.AddLogicalChild(ribbonControl); - } - } - - var oldRibbonControl = e.OldValue as IRibbonControl; - - if (oldRibbonControl!=null) - { - var parent = LogicalTreeHelper.GetParent((DependencyObject)oldRibbonControl); - if (parent == quickAccessMenuItem) - { - quickAccessMenuItem.RemoveLogicalChild(oldRibbonControl); - } - } - } - - #endregion - - #region Overrides - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - if (this.Target != null) - { - var parent = LogicalTreeHelper.GetParent(this.Target); - if (ReferenceEquals(parent, this)) - { - var list = new ArrayList { this.Target }; - return list.GetEnumerator(); - } - } - - return base.LogicalChildren; - } - } - - #endregion - - #region Event Handlers - - private void OnChecked(object sender, RoutedEventArgs e) - { - if (this.Ribbon != null) - { - this.Ribbon.AddToQuickAccessToolBar(this.Target); - } - } - - private void OnUnchecked(object sender, RoutedEventArgs e) - { - if (!this.IsLoaded) - { - return; - } - - if (this.Ribbon != null) - { - this.Ribbon.RemoveFromQuickAccessToolBar(this.Target); - } - } - - private void OnItemLoaded(object sender, RoutedEventArgs e) - { - if (!this.IsLoaded) - { - return; - } - - if (this.Ribbon != null) - { - this.IsChecked = this.Ribbon.IsInQuickAccessToolBar(this.Target); - } - } - - private void OnFirstLoaded(object sender, RoutedEventArgs e) - { - this.Loaded -= this.OnFirstLoaded; - if (this.IsChecked - && this.Ribbon != null) - { - this.Ribbon.AddToQuickAccessToolBar(this.Target); - } - } - - #endregion - } - - /// - /// The class responds to mine controls for QuickAccessToolBar - /// - internal static class QuickAccessItemsProvider - { - #region Public Methods - - /// - /// Determines whether the given control can provide a quick access toolbar item - /// - /// Control - /// True if this control is able to provide - /// a quick access toolbar item, false otherwise - public static bool IsSupported(UIElement element) - { - var provider = element as IQuickAccessItemProvider; - if (provider != null - && provider.CanAddToQuickAccessToolBar) - { - return true; - } - - return false; - } - - /// - /// Gets control which represents quick access toolbar item - /// - /// Host control - /// Control which represents quick access toolbar item - [SuppressMessage("Microsoft.Performance", "CA1800")] - public static FrameworkElement GetQuickAccessItem(UIElement element) - { - FrameworkElement result = null; - - // If control supports the interface just return what it provides - var provider = element as IQuickAccessItemProvider; - if (provider != null - && provider.CanAddToQuickAccessToolBar) - { - result = ((IQuickAccessItemProvider)element).CreateQuickAccessItem(); - } - - // The control isn't supported - if (result == null) - { - throw new ArgumentException("The contol " + element.GetType().Name + " is not able to provide a quick access toolbar item"); - } - - if (BindingOperations.IsDataBound(result, UIElement.VisibilityProperty) == false) - { - RibbonControl.Bind(element, result, "Visibility", UIElement.VisibilityProperty, BindingMode.OneWay); - } - - if (BindingOperations.IsDataBound(result, UIElement.IsEnabledProperty) == false) - { - RibbonControl.Bind(element, result, "IsEnabled", UIElement.IsEnabledProperty, BindingMode.OneWay); - } - - return result; - } - - /// - /// Finds the top supported control - /// - /// Visual - /// Point - /// Point - public static FrameworkElement FindSupportedControl(Visual visual, Point point) - { - var result = VisualTreeHelper.HitTest(visual, point); - if (result == null) - { - return null; - } - - // Try to find in visual (or logical) tree - var element = result.VisualHit as FrameworkElement; - while (element != null) - { - if (IsSupported(element)) - { - return element; - } - - var visualParent = VisualTreeHelper.GetParent(element) as FrameworkElement; - var logicalParent = LogicalTreeHelper.GetParent(element) as FrameworkElement; - element = visualParent ?? logicalParent; - } - - return null; - } - - #endregion - } +using System; +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Controls; + +namespace Fluent +{ + /// + /// This interface must be implemented for controls + /// which are intended to insert to quick access toolbar + /// + public interface IQuickAccessItemProvider + { + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + FrameworkElement CreateQuickAccessItem(); + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + bool CanAddToQuickAccessToolBar { get; set; } + } + + /// + /// Peresents quick access shortcut to another control + /// + [ContentProperty("Target")] + public class QuickAccessMenuItem : MenuItem + { + #region Fields + + internal Ribbon Ribbon; + + #endregion + + #region Initialization + + [SuppressMessage("Microsoft.Performance", "CA1810")] + static QuickAccessMenuItem() + { + IsCheckableProperty.AddOwner(typeof(QuickAccessMenuItem), new FrameworkPropertyMetadata(true)); + } + + /// + /// Default constructor + /// + public QuickAccessMenuItem() + { + this.Checked += this.OnChecked; + this.Unchecked += this.OnUnchecked; + this.Loaded += this.OnFirstLoaded; + this.Loaded += this.OnItemLoaded; + } + + #endregion + + #region Target Property + + /// + /// Gets or sets shortcut to the target control + /// + public Control Target + { + get { return (Control)this.GetValue(TargetProperty); } + set { this.SetValue(TargetProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for shortcut. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TargetProperty = + DependencyProperty.Register("Target", typeof(Control), typeof(QuickAccessMenuItem), new UIPropertyMetadata(null,OnTargetChanged)); + + private static void OnTargetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var quickAccessMenuItem = (QuickAccessMenuItem)d; + var ribbonControl = e.NewValue as IRibbonControl; + + if (quickAccessMenuItem.Header == null + && ribbonControl != null) + { + // Set Default Text Value + RibbonControl.Bind(ribbonControl, quickAccessMenuItem, "Header", HeaderProperty, BindingMode.OneWay); + } + + if (ribbonControl != null) + { + var parent = LogicalTreeHelper.GetParent((DependencyObject)ribbonControl); + if (parent == null) + { + quickAccessMenuItem.AddLogicalChild(ribbonControl); + } + } + + var oldRibbonControl = e.OldValue as IRibbonControl; + + if (oldRibbonControl!=null) + { + var parent = LogicalTreeHelper.GetParent((DependencyObject)oldRibbonControl); + if (parent == quickAccessMenuItem) + { + quickAccessMenuItem.RemoveLogicalChild(oldRibbonControl); + } + } + } + + #endregion + + #region Overrides + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + if (this.Target != null) + { + var parent = LogicalTreeHelper.GetParent(this.Target); + if (ReferenceEquals(parent, this)) + { + var list = new ArrayList { this.Target }; + return list.GetEnumerator(); + } + } + + return base.LogicalChildren; + } + } + + #endregion + + #region Event Handlers + + private void OnChecked(object sender, RoutedEventArgs e) + { + if (this.Ribbon != null) + { + this.Ribbon.AddToQuickAccessToolBar(this.Target); + } + } + + private void OnUnchecked(object sender, RoutedEventArgs e) + { + if (!this.IsLoaded) + { + return; + } + + if (this.Ribbon != null) + { + this.Ribbon.RemoveFromQuickAccessToolBar(this.Target); + } + } + + private void OnItemLoaded(object sender, RoutedEventArgs e) + { + if (!this.IsLoaded) + { + return; + } + + if (this.Ribbon != null) + { + this.IsChecked = this.Ribbon.IsInQuickAccessToolBar(this.Target); + } + } + + private void OnFirstLoaded(object sender, RoutedEventArgs e) + { + this.Loaded -= this.OnFirstLoaded; + if (this.IsChecked + && this.Ribbon != null) + { + this.Ribbon.AddToQuickAccessToolBar(this.Target); + } + } + + #endregion + } + + /// + /// The class responds to mine controls for QuickAccessToolBar + /// + internal static class QuickAccessItemsProvider + { + #region Public Methods + + /// + /// Determines whether the given control can provide a quick access toolbar item + /// + /// Control + /// True if this control is able to provide + /// a quick access toolbar item, false otherwise + public static bool IsSupported(UIElement element) + { + var provider = element as IQuickAccessItemProvider; + if (provider != null + && provider.CanAddToQuickAccessToolBar) + { + return true; + } + + return false; + } + + /// + /// Gets control which represents quick access toolbar item + /// + /// Host control + /// Control which represents quick access toolbar item + [SuppressMessage("Microsoft.Performance", "CA1800")] + public static FrameworkElement GetQuickAccessItem(UIElement element) + { + FrameworkElement result = null; + + // If control supports the interface just return what it provides + var provider = element as IQuickAccessItemProvider; + if (provider != null + && provider.CanAddToQuickAccessToolBar) + { + result = ((IQuickAccessItemProvider)element).CreateQuickAccessItem(); + } + + // The control isn't supported + if (result == null) + { + throw new ArgumentException("The contol " + element.GetType().Name + " is not able to provide a quick access toolbar item"); + } + + if (BindingOperations.IsDataBound(result, UIElement.VisibilityProperty) == false) + { + RibbonControl.Bind(element, result, "Visibility", UIElement.VisibilityProperty, BindingMode.OneWay); + } + + if (BindingOperations.IsDataBound(result, UIElement.IsEnabledProperty) == false) + { + RibbonControl.Bind(element, result, "IsEnabled", UIElement.IsEnabledProperty, BindingMode.OneWay); + } + + return result; + } + + /// + /// Finds the top supported control + /// + /// Visual + /// Point + /// Point + public static FrameworkElement FindSupportedControl(Visual visual, Point point) + { + var result = VisualTreeHelper.HitTest(visual, point); + if (result == null) + { + return null; + } + + // Try to find in visual (or logical) tree + var element = result.VisualHit as FrameworkElement; + while (element != null) + { + if (IsSupported(element)) + { + return element; + } + + var visualParent = VisualTreeHelper.GetParent(element) as FrameworkElement; + var logicalParent = LogicalTreeHelper.GetParent(element) as FrameworkElement; + element = visualParent ?? logicalParent; + } + + return null; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/QuickAccessToolBar.cs b/Fluent.Ribbon/Controls/QuickAccessToolBar.cs similarity index 95% rename from Fluent/Controls/QuickAccessToolBar.cs rename to Fluent.Ribbon/Controls/QuickAccessToolBar.cs index 094f2e7e4..6b5fbe046 100644 --- a/Fluent/Controls/QuickAccessToolBar.cs +++ b/Fluent.Ribbon/Controls/QuickAccessToolBar.cs @@ -1,626 +1,617 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Collections; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Linq; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Markup; - using Fluent.Internal; - - /// - /// Represents quick access toolbar - /// - [TemplatePart(Name = "PART_ShowAbove", Type = typeof(MenuItem))] - [TemplatePart(Name = "PART_ShowBelow", Type = typeof(MenuItem))] - [TemplatePart(Name = "PART_MenuPanel", Type = typeof(Panel))] - [TemplatePart(Name = "PART_RootPanel", Type = typeof(Panel))] - [ContentProperty("QuickAccessItems")] - public class QuickAccessToolBar : Control - { - #region Events - - /// - /// Occured when items are added or removed from Quick Access toolbar - /// - public event NotifyCollectionChangedEventHandler ItemsChanged = delegate { }; - - #endregion - - #region Fields - - private DropDownButton toolBarDownButton; - - private DropDownButton menuDownButton; - - // Show above menu item - private MenuItem showAbove; - - // Show below menu item - private MenuItem showBelow; - - // Items of quick access menu - private ObservableCollection quickAccessItems; - - // Root panel - private Panel rootPanel; - - // ToolBar panel - private Panel toolBarPanel; - - // ToolBar overflow panel - private Panel toolBarOverflowPanel; - - // Items of quick access menu - private ObservableCollection items; - - private Size cachedConstraint; - private int cachedNonOverflowItemsCount = -1; - - // Itemc collection was changed - private bool itemsHadChanged; - - private double cachedDeltaWidth; - - #endregion - - #region Properties - - #region Items - - /// - /// Gets items collection - /// - internal ObservableCollection Items - { - get - { - if (this.items == null) - { - this.items = new ObservableCollection(); - this.items.CollectionChanged += this.OnItemsCollectionChanged; - } - - return this.items; - } - } - - private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.cachedNonOverflowItemsCount = this.GetNonOverflowItemsCount(this.DesiredSize.Width); - this.UpdateHasOverflowItems(); - this.itemsHadChanged = true; - this.InvalidateMeasure(); - - this.InvalidateMeasureOfParentRibbon(); - - this.UpdateKeyTips(); - - if (e.OldItems != null) - { - foreach (var item in e.OldItems.OfType()) - { - item.SizeChanged -= this.OnChildSizeChanged; - } - } - - if (e.NewItems != null) - { - foreach (var item in e.NewItems.OfType()) - { - item.SizeChanged += this.OnChildSizeChanged; - } - } - - if (e.Action == NotifyCollectionChangedAction.Reset) - { - foreach (var item in this.Items.OfType()) - { - item.SizeChanged -= this.OnChildSizeChanged; - } - } - - // Raise items changed event - this.ItemsChanged(this, e); - } - - private void OnChildSizeChanged(object sender, SizeChangedEventArgs e) - { - this.InvalidateMeasureOfParentRibbon(); - } - - #endregion - - #region HasOverflowItems - - /// - /// Gets whether QuickAccessToolBar has overflow items - /// - public bool HasOverflowItems - { - get { return (bool)this.GetValue(HasOverflowItemsProperty); } - private set { this.SetValue(HasOverflowItemsPropertyKey, value); } - } - - private static readonly DependencyPropertyKey HasOverflowItemsPropertyKey = - DependencyProperty.RegisterReadOnly("HasOverflowItems", typeof(bool), typeof(QuickAccessToolBar), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for HasOverflowItems. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasOverflowItemsProperty = HasOverflowItemsPropertyKey.DependencyProperty; - - #endregion - - #region QuickAccessItems - - /// - /// Gets quick access menu items - /// - public ObservableCollection QuickAccessItems - { - get - { - if (this.quickAccessItems == null) - { - this.quickAccessItems = new ObservableCollection(); - this.quickAccessItems.CollectionChanged += this.OnQuickAccessItemsCollectionChanged; - } - - return this.quickAccessItems; - } - } - - /// - /// Handles quick access menu items chages - /// - /// - /// - private void OnQuickAccessItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (var i = 0; i < e.NewItems.Count; i++) - { - if (this.menuDownButton != null) - { - this.menuDownButton.Items.Insert(e.NewStartingIndex + i + 1, e.NewItems[i]); - } - else - { - this.AddLogicalChild(e.NewItems[i]); - } - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (var item in e.OldItems) - { - if (this.menuDownButton != null) - { - this.menuDownButton.Items.Remove(item); - } - else - { - this.RemoveLogicalChild(item); - } - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var item in e.OldItems) - { - if (this.menuDownButton != null) - { - this.menuDownButton.Items.Remove(item); - } - else - { - this.RemoveLogicalChild(item); - } - } - - var ii = 0; - foreach (var item in e.NewItems) - { - if (this.menuDownButton != null) - { - this.menuDownButton.Items.Insert(e.NewStartingIndex + ii + 1, item); - } - else - { - this.AddLogicalChild(item); - } - - ii++; - } - break; - } - } - - #endregion - - #region ShowAboveRibbon - - /// - /// Gets or sets whether quick access toolbar showes above ribbon - /// - public bool ShowAboveRibbon - { - get { return (bool)this.GetValue(ShowAboveRibbonProperty); } - set { this.SetValue(ShowAboveRibbonProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ShowAboveRibbon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ShowAboveRibbonProperty = - DependencyProperty.Register("ShowAboveRibbon", typeof(bool), - typeof(QuickAccessToolBar), new UIPropertyMetadata(true)); - - #endregion - - #region LogicalChildren - - /// - /// Gets an enumerator to the logical child elements - /// - protected override IEnumerator LogicalChildren - { - get - { - yield return this.rootPanel; - } - } - - #endregion - - #region CanQuickAccessLocationChanging - - /// - /// Gets or sets whether user can change location of QAT - /// - public bool CanQuickAccessLocationChanging - { - get { return (bool)this.GetValue(CanQuickAccessLocationChangingProperty); } - set { this.SetValue(CanQuickAccessLocationChangingProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanQuickAccessLocationChanging. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanQuickAccessLocationChangingProperty = - DependencyProperty.Register("CanQuickAccessLocationChanging", typeof(bool), typeof(QuickAccessToolBar), new UIPropertyMetadata(true)); - - #endregion - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static QuickAccessToolBar() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(QuickAccessToolBar), new FrameworkPropertyMetadata(typeof(QuickAccessToolBar))); - StyleProperty.OverrideMetadata(typeof(QuickAccessToolBar), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - // Coerce object style - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(QuickAccessToolBar)); - } - - return basevalue; - } - - #endregion - - #region Override - - /// - /// When overridden in a derived class, is invoked whenever application code or - /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). - /// - public override void OnApplyTemplate() - { - if (this.showAbove != null) - { - this.showAbove.Click -= this.OnShowAboveClick; - } - - if (this.showBelow != null) - { - this.showBelow.Click -= this.OnShowBelowClick; - } - - this.showAbove = this.GetTemplateChild("PART_ShowAbove") as MenuItem; - this.showBelow = this.GetTemplateChild("PART_ShowBelow") as MenuItem; - - if (this.showAbove != null) - { - this.showAbove.Click += this.OnShowAboveClick; - } - - if (this.showBelow != null) - { - this.showBelow.Click += this.OnShowBelowClick; - } - - if (this.menuDownButton != null) - { - foreach (var item in this.QuickAccessItems) - { - this.menuDownButton.Items.Remove(item); - item.InvalidateProperty(QuickAccessMenuItem.TargetProperty); - } - } - else if (this.quickAccessItems != null) - { - foreach (var item in this.quickAccessItems) - { - this.RemoveLogicalChild(item); - } - } - - this.menuDownButton = this.GetTemplateChild("PART_MenuDownButton") as DropDownButton; - - if (this.menuDownButton != null - && this.quickAccessItems != null) - { - for (var i = 0; i < this.quickAccessItems.Count; i++) - { - this.menuDownButton.Items.Insert(i + 1, this.quickAccessItems[i]); - this.quickAccessItems[i].InvalidateProperty(QuickAccessMenuItem.TargetProperty); - } - } - - if (this.toolBarDownButton != null) - { - this.toolBarDownButton.DropDownOpened -= this.OnToolBarDownOpened; - this.toolBarDownButton.DropDownClosed -= this.OnToolBarDownClosed; - } - - this.toolBarDownButton = this.GetTemplateChild("PART_ToolbarDownButton") as DropDownButton; - - if (this.toolBarDownButton != null) - { - this.toolBarDownButton.DropDownOpened += this.OnToolBarDownOpened; - this.toolBarDownButton.DropDownClosed += this.OnToolBarDownClosed; - } - - // ToolBar panels - this.toolBarPanel = this.GetTemplateChild("PART_ToolBarPanel") as Panel; - this.toolBarOverflowPanel = this.GetTemplateChild("PART_ToolBarOverflowPanel") as Panel; - - if (this.rootPanel != null) - { - this.RemoveLogicalChild(this.rootPanel); - } - - this.rootPanel = this.GetTemplateChild("PART_RootPanel") as Panel; - - if (this.rootPanel != null) - { - this.AddLogicalChild(this.rootPanel); - } - - // Clears cache - this.cachedDeltaWidth = 0; - this.cachedNonOverflowItemsCount = this.GetNonOverflowItemsCount(this.ActualWidth); - this.cachedConstraint = new Size(); - } - - private void OnToolBarDownClosed(object sender, EventArgs e) - { - this.toolBarOverflowPanel.Children.Clear(); - } - - private void OnToolBarDownOpened(object sender, EventArgs e) - { - if (this.toolBarOverflowPanel.Children.Count > 0) - { - this.toolBarOverflowPanel.Children.Clear(); - } - - for (var i = this.cachedNonOverflowItemsCount; i < this.Items.Count; i++) - { - this.toolBarOverflowPanel.Children.Add(this.Items[i]); - } - } - - /// - /// Handles show below menu item click - /// - /// Sender - /// The event data - private void OnShowBelowClick(object sender, RoutedEventArgs e) - { - this.ShowAboveRibbon = false; - } - - /// - /// Handles show above menu item click - /// - /// Sender - /// The event data - private void OnShowAboveClick(object sender, RoutedEventArgs e) - { - this.ShowAboveRibbon = true; - } - - /// - /// Called to remeasure a control. - /// - /// The size of the control, up to the maximum specified by constraint - /// The maximum size that the method can return - protected override Size MeasureOverride(Size constraint) - { - if ((this.cachedConstraint == constraint) - && !this.itemsHadChanged) - { - return base.MeasureOverride(constraint); - } - - var nonOverflowItemsCount = this.GetNonOverflowItemsCount(constraint.Width); - - if (this.itemsHadChanged == false - && nonOverflowItemsCount == this.cachedNonOverflowItemsCount) - { - return base.MeasureOverride(constraint); - } - - this.cachedNonOverflowItemsCount = nonOverflowItemsCount; - this.UpdateHasOverflowItems(); - this.cachedConstraint = constraint; - - if (this.HasOverflowItems == false) - { - this.toolBarOverflowPanel.Children.Clear(); - } - - if (this.itemsHadChanged) - { - // Refill toolbar - this.toolBarPanel.Children.Clear(); - - for (var i = 0; i < this.cachedNonOverflowItemsCount; i++) - { - this.toolBarPanel.Children.Add(this.Items[i]); - } - - this.itemsHadChanged = false; - } - else - { - if (this.cachedNonOverflowItemsCount > this.toolBarPanel.Children.Count) - { - // Add needed items - var savedCount = this.toolBarPanel.Children.Count; - for (var i = savedCount; i < this.cachedNonOverflowItemsCount; i++) - { - this.toolBarPanel.Children.Add(this.Items[i]); - } - } - else - { - // Remove nonneeded items - for (var i = this.toolBarPanel.Children.Count - 1; i >= this.cachedNonOverflowItemsCount; i--) - { - this.toolBarPanel.Children.Remove(this.Items[i]); - } - } - } - - return base.MeasureOverride(constraint); - } - - /// - /// We have to use this function because setting a very frequently is quite expensive - /// - private void UpdateHasOverflowItems() - { - var newValue = this.cachedNonOverflowItemsCount < this.Items.Count; - - // ReSharper disable RedundantCheckBeforeAssignment - if (this.HasOverflowItems != newValue) - // ReSharper restore RedundantCheckBeforeAssignment - { - this.HasOverflowItems = newValue; - } - } - - #endregion - - #region Methods - - /// - /// First calls and then - /// - public void Refresh() - { - this.InvalidateMeasure(); - this.InvalidateMeasureOfParentRibbon(); - } - - private void InvalidateMeasureOfParentRibbon() - { - var parentRibbon = this.Parent as Ribbon; - - if (parentRibbon != null) - { - parentRibbon.TitleBar.InvalidateMeasure(); - } - } - - // Updates keys for keytip access - private void UpdateKeyTips() - { - for (var i = 0; i < Math.Min(9, this.Items.Count); i++) - { - // 1, 2, 3, ... , 9 - KeyTip.SetKeys(this.Items[i], (i + 1).ToString(CultureInfo.InvariantCulture)); - } - - for (var i = 9; i < Math.Min(18, this.Items.Count); i++) - { - // 09, 08, 07, ... , 01 - KeyTip.SetKeys(this.Items[i], "0" + (18 - i).ToString(CultureInfo.InvariantCulture)); - } - - var startChar = 'A'; - for (var i = 18; i < Math.Min(9 + 9 + 26, this.Items.Count); i++) - { - // 0A, 0B, 0C, ... , 0Z - KeyTip.SetKeys(this.Items[i], "0" + startChar++); - } - } - - private int GetNonOverflowItemsCount(double width) - { - if (DoubleUtil.AreClose(this.cachedDeltaWidth, 0) - && this.rootPanel != null - && this.toolBarPanel != null) - { - this.rootPanel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - this.cachedDeltaWidth = this.rootPanel.DesiredSize.Width - this.toolBarPanel.DesiredSize.Width; - } - - var currentWidth = 0D; - for (var i = 0; i < this.Items.Count; i++) - { - this.Items[i].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - currentWidth += this.Items[i].DesiredSize.Width; - - if (currentWidth + this.cachedDeltaWidth > width) - { - return i; - } - } - - return this.Items.Count; - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Linq; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Markup; + using Fluent.Internal; + + /// + /// Represents quick access toolbar + /// + [TemplatePart(Name = "PART_ShowAbove", Type = typeof(MenuItem))] + [TemplatePart(Name = "PART_ShowBelow", Type = typeof(MenuItem))] + [TemplatePart(Name = "PART_MenuPanel", Type = typeof(Panel))] + [TemplatePart(Name = "PART_RootPanel", Type = typeof(Panel))] + [ContentProperty("QuickAccessItems")] + public class QuickAccessToolBar : Control + { + #region Events + + /// + /// Occured when items are added or removed from Quick Access toolbar + /// + public event NotifyCollectionChangedEventHandler ItemsChanged = delegate { }; + + #endregion + + #region Fields + + private DropDownButton toolBarDownButton; + + private DropDownButton menuDownButton; + + // Show above menu item + private MenuItem showAbove; + + // Show below menu item + private MenuItem showBelow; + + // Items of quick access menu + private ObservableCollection quickAccessItems; + + // Root panel + private Panel rootPanel; + + // ToolBar panel + private Panel toolBarPanel; + + // ToolBar overflow panel + private Panel toolBarOverflowPanel; + + // Items of quick access menu + private ObservableCollection items; + + private Size cachedConstraint; + private int cachedNonOverflowItemsCount = -1; + + // Itemc collection was changed + private bool itemsHadChanged; + + private double cachedDeltaWidth; + + #endregion + + #region Properties + + #region Items + + /// + /// Gets items collection + /// + internal ObservableCollection Items + { + get + { + if (this.items == null) + { + this.items = new ObservableCollection(); + this.items.CollectionChanged += this.OnItemsCollectionChanged; + } + + return this.items; + } + } + + private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.cachedNonOverflowItemsCount = this.GetNonOverflowItemsCount(this.DesiredSize.Width); + this.UpdateHasOverflowItems(); + this.itemsHadChanged = true; + this.InvalidateMeasure(); + + this.InvalidateMeasureOfParentRibbon(); + + this.UpdateKeyTips(); + + if (e.OldItems != null) + { + foreach (var item in e.OldItems.OfType()) + { + item.SizeChanged -= this.OnChildSizeChanged; + } + } + + if (e.NewItems != null) + { + foreach (var item in e.NewItems.OfType()) + { + item.SizeChanged += this.OnChildSizeChanged; + } + } + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + foreach (var item in this.Items.OfType()) + { + item.SizeChanged -= this.OnChildSizeChanged; + } + } + + // Raise items changed event + this.ItemsChanged(this, e); + } + + private void OnChildSizeChanged(object sender, SizeChangedEventArgs e) + { + this.InvalidateMeasureOfParentRibbon(); + } + + #endregion + + #region HasOverflowItems + + /// + /// Gets whether QuickAccessToolBar has overflow items + /// + public bool HasOverflowItems + { + get { return (bool)this.GetValue(HasOverflowItemsProperty); } + private set { this.SetValue(HasOverflowItemsPropertyKey, value); } + } + + private static readonly DependencyPropertyKey HasOverflowItemsPropertyKey = + DependencyProperty.RegisterReadOnly("HasOverflowItems", typeof(bool), typeof(QuickAccessToolBar), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for HasOverflowItems. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasOverflowItemsProperty = HasOverflowItemsPropertyKey.DependencyProperty; + + #endregion + + #region QuickAccessItems + + /// + /// Gets quick access menu items + /// + public ObservableCollection QuickAccessItems + { + get + { + if (this.quickAccessItems == null) + { + this.quickAccessItems = new ObservableCollection(); + this.quickAccessItems.CollectionChanged += this.OnQuickAccessItemsCollectionChanged; + } + + return this.quickAccessItems; + } + } + + /// + /// Handles quick access menu items chages + /// + /// + /// + private void OnQuickAccessItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (var i = 0; i < e.NewItems.Count; i++) + { + if (this.menuDownButton != null) + { + this.menuDownButton.Items.Insert(e.NewStartingIndex + i + 1, e.NewItems[i]); + } + else + { + this.AddLogicalChild(e.NewItems[i]); + } + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems) + { + if (this.menuDownButton != null) + { + this.menuDownButton.Items.Remove(item); + } + else + { + this.RemoveLogicalChild(item); + } + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var item in e.OldItems) + { + if (this.menuDownButton != null) + { + this.menuDownButton.Items.Remove(item); + } + else + { + this.RemoveLogicalChild(item); + } + } + + var ii = 0; + foreach (var item in e.NewItems) + { + if (this.menuDownButton != null) + { + this.menuDownButton.Items.Insert(e.NewStartingIndex + ii + 1, item); + } + else + { + this.AddLogicalChild(item); + } + + ii++; + } + break; + } + } + + #endregion + + #region ShowAboveRibbon + + /// + /// Gets or sets whether quick access toolbar showes above ribbon + /// + public bool ShowAboveRibbon + { + get { return (bool)this.GetValue(ShowAboveRibbonProperty); } + set { this.SetValue(ShowAboveRibbonProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ShowAboveRibbon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ShowAboveRibbonProperty = + DependencyProperty.Register("ShowAboveRibbon", typeof(bool), + typeof(QuickAccessToolBar), new UIPropertyMetadata(true)); + + #endregion + + #region LogicalChildren + + /// + /// Gets an enumerator to the logical child elements + /// + protected override IEnumerator LogicalChildren + { + get + { + yield return this.rootPanel; + } + } + + #endregion + + #region CanQuickAccessLocationChanging + + /// + /// Gets or sets whether user can change location of QAT + /// + public bool CanQuickAccessLocationChanging + { + get { return (bool)this.GetValue(CanQuickAccessLocationChangingProperty); } + set { this.SetValue(CanQuickAccessLocationChangingProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanQuickAccessLocationChanging. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanQuickAccessLocationChangingProperty = + DependencyProperty.Register("CanQuickAccessLocationChanging", typeof(bool), typeof(QuickAccessToolBar), new UIPropertyMetadata(true)); + + #endregion + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static QuickAccessToolBar() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(QuickAccessToolBar), new FrameworkPropertyMetadata(typeof(QuickAccessToolBar))); + StyleProperty.OverrideMetadata(typeof(QuickAccessToolBar), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(QuickAccessToolBar)); + } + + return basevalue; + } + + #endregion + + #region Override + + /// + /// When overridden in a derived class, is invoked whenever application code or + /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). + /// + public override void OnApplyTemplate() + { + if (this.showAbove != null) + { + this.showAbove.Click -= this.OnShowAboveClick; + } + + if (this.showBelow != null) + { + this.showBelow.Click -= this.OnShowBelowClick; + } + + this.showAbove = this.GetTemplateChild("PART_ShowAbove") as MenuItem; + this.showBelow = this.GetTemplateChild("PART_ShowBelow") as MenuItem; + + if (this.showAbove != null) + { + this.showAbove.Click += this.OnShowAboveClick; + } + + if (this.showBelow != null) + { + this.showBelow.Click += this.OnShowBelowClick; + } + + if (this.menuDownButton != null) + { + foreach (var item in this.QuickAccessItems) + { + this.menuDownButton.Items.Remove(item); + item.InvalidateProperty(QuickAccessMenuItem.TargetProperty); + } + } + else if (this.quickAccessItems != null) + { + foreach (var item in this.quickAccessItems) + { + this.RemoveLogicalChild(item); + } + } + + this.menuDownButton = this.GetTemplateChild("PART_MenuDownButton") as DropDownButton; + + if (this.menuDownButton != null + && this.quickAccessItems != null) + { + for (var i = 0; i < this.quickAccessItems.Count; i++) + { + this.menuDownButton.Items.Insert(i + 1, this.quickAccessItems[i]); + this.quickAccessItems[i].InvalidateProperty(QuickAccessMenuItem.TargetProperty); + } + } + + if (this.toolBarDownButton != null) + { + this.toolBarDownButton.DropDownOpened -= this.OnToolBarDownOpened; + this.toolBarDownButton.DropDownClosed -= this.OnToolBarDownClosed; + } + + this.toolBarDownButton = this.GetTemplateChild("PART_ToolbarDownButton") as DropDownButton; + + if (this.toolBarDownButton != null) + { + this.toolBarDownButton.DropDownOpened += this.OnToolBarDownOpened; + this.toolBarDownButton.DropDownClosed += this.OnToolBarDownClosed; + } + + // ToolBar panels + this.toolBarPanel = this.GetTemplateChild("PART_ToolBarPanel") as Panel; + this.toolBarOverflowPanel = this.GetTemplateChild("PART_ToolBarOverflowPanel") as Panel; + + if (this.rootPanel != null) + { + this.RemoveLogicalChild(this.rootPanel); + } + + this.rootPanel = this.GetTemplateChild("PART_RootPanel") as Panel; + + if (this.rootPanel != null) + { + this.AddLogicalChild(this.rootPanel); + } + + // Clears cache + this.cachedDeltaWidth = 0; + this.cachedNonOverflowItemsCount = this.GetNonOverflowItemsCount(this.ActualWidth); + this.cachedConstraint = new Size(); + } + + private void OnToolBarDownClosed(object sender, EventArgs e) + { + this.toolBarOverflowPanel.Children.Clear(); + } + + private void OnToolBarDownOpened(object sender, EventArgs e) + { + if (this.toolBarOverflowPanel.Children.Count > 0) + { + this.toolBarOverflowPanel.Children.Clear(); + } + + for (var i = this.cachedNonOverflowItemsCount; i < this.Items.Count; i++) + { + this.toolBarOverflowPanel.Children.Add(this.Items[i]); + } + } + + /// + /// Handles show below menu item click + /// + /// Sender + /// The event data + private void OnShowBelowClick(object sender, RoutedEventArgs e) + { + this.ShowAboveRibbon = false; + } + + /// + /// Handles show above menu item click + /// + /// Sender + /// The event data + private void OnShowAboveClick(object sender, RoutedEventArgs e) + { + this.ShowAboveRibbon = true; + } + + /// + /// Called to remeasure a control. + /// + /// The size of the control, up to the maximum specified by constraint + /// The maximum size that the method can return + protected override Size MeasureOverride(Size constraint) + { + if ((this.cachedConstraint == constraint) + && !this.itemsHadChanged) + { + return base.MeasureOverride(constraint); + } + + var nonOverflowItemsCount = this.GetNonOverflowItemsCount(constraint.Width); + + if (this.itemsHadChanged == false + && nonOverflowItemsCount == this.cachedNonOverflowItemsCount) + { + return base.MeasureOverride(constraint); + } + + this.cachedNonOverflowItemsCount = nonOverflowItemsCount; + this.UpdateHasOverflowItems(); + this.cachedConstraint = constraint; + + if (this.HasOverflowItems == false) + { + this.toolBarOverflowPanel.Children.Clear(); + } + + if (this.itemsHadChanged) + { + // Refill toolbar + this.toolBarPanel.Children.Clear(); + + for (var i = 0; i < this.cachedNonOverflowItemsCount; i++) + { + this.toolBarPanel.Children.Add(this.Items[i]); + } + + this.itemsHadChanged = false; + } + else + { + if (this.cachedNonOverflowItemsCount > this.toolBarPanel.Children.Count) + { + // Add needed items + var savedCount = this.toolBarPanel.Children.Count; + for (var i = savedCount; i < this.cachedNonOverflowItemsCount; i++) + { + this.toolBarPanel.Children.Add(this.Items[i]); + } + } + else + { + // Remove nonneeded items + for (var i = this.toolBarPanel.Children.Count - 1; i >= this.cachedNonOverflowItemsCount; i--) + { + this.toolBarPanel.Children.Remove(this.Items[i]); + } + } + } + + return base.MeasureOverride(constraint); + } + + /// + /// We have to use this function because setting a very frequently is quite expensive + /// + private void UpdateHasOverflowItems() + { + var newValue = this.cachedNonOverflowItemsCount < this.Items.Count; + + // ReSharper disable RedundantCheckBeforeAssignment + if (this.HasOverflowItems != newValue) + // ReSharper restore RedundantCheckBeforeAssignment + { + this.HasOverflowItems = newValue; + } + } + + #endregion + + #region Methods + + /// + /// First calls and then + /// + public void Refresh() + { + this.InvalidateMeasure(); + this.InvalidateMeasureOfParentRibbon(); + } + + private void InvalidateMeasureOfParentRibbon() + { + var parentRibbon = this.Parent as Ribbon; + + if (parentRibbon != null) + { + parentRibbon.TitleBar.InvalidateMeasure(); + } + } + + // Updates keys for keytip access + private void UpdateKeyTips() + { + for (var i = 0; i < Math.Min(9, this.Items.Count); i++) + { + // 1, 2, 3, ... , 9 + KeyTip.SetKeys(this.Items[i], (i + 1).ToString(CultureInfo.InvariantCulture)); + } + + for (var i = 9; i < Math.Min(18, this.Items.Count); i++) + { + // 09, 08, 07, ... , 01 + KeyTip.SetKeys(this.Items[i], "0" + (18 - i).ToString(CultureInfo.InvariantCulture)); + } + + var startChar = 'A'; + for (var i = 18; i < Math.Min(9 + 9 + 26, this.Items.Count); i++) + { + // 0A, 0B, 0C, ... , 0Z + KeyTip.SetKeys(this.Items[i], "0" + startChar++); + } + } + + private int GetNonOverflowItemsCount(double width) + { + if (DoubleUtil.AreClose(this.cachedDeltaWidth, 0) + && this.rootPanel != null + && this.toolBarPanel != null) + { + this.rootPanel.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + this.cachedDeltaWidth = this.rootPanel.DesiredSize.Width - this.toolBarPanel.DesiredSize.Width; + } + + var currentWidth = 0D; + for (var i = 0; i < this.Items.Count; i++) + { + this.Items[i].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + currentWidth += this.Items[i].DesiredSize.Width; + + if (currentWidth + this.cachedDeltaWidth > width) + { + return i; + } + } + + return this.Items.Count; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RadioButton.cs b/Fluent.Ribbon/Controls/RadioButton.cs similarity index 77% rename from Fluent/Controls/RadioButton.cs rename to Fluent.Ribbon/Controls/RadioButton.cs index c43c91517..a783949d4 100644 --- a/Fluent/Controls/RadioButton.cs +++ b/Fluent.Ribbon/Controls/RadioButton.cs @@ -1,245 +1,228 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents Fluent UI specific RadioButton - /// - [ContentProperty("Header")] - public class RadioButton : System.Windows.Controls.RadioButton, IRibbonControl, IQuickAccessItemProvider - { - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RadioButton)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RadioButton)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RadioButton)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(RadioButton)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return (ImageSource)this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RadioButton), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RadioButton element = d as RadioButton; - FrameworkElement oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - FrameworkElement newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - - #endregion - - #region LargeIcon - - /// - /// Gets or sets button large icon - /// - public ImageSource LargeIcon - { - get { return (ImageSource)this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(ImageSource), - typeof(RadioButton), new UIPropertyMetadata(null)); - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RadioButton() - { - Type type = typeof(RadioButton); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - ContextMenuService.Attach(type); - ToolTipService.Attach(type); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - //basevalue = (d as FrameworkElement).TryFindResource(typeof(QuickAccessToolBar)); - basevalue = (d as FrameworkElement).TryFindResource(typeof(RadioButton)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public RadioButton() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - RadioButton button = new RadioButton(); - - RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); - button.Click += ((sender, e) => this.RaiseEvent(e)); - RibbonControl.BindQuickAccessItem(this, button); - - return button; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(RadioButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IKeyTipedControl - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.OnClick(); - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents Fluent UI specific RadioButton + /// + [ContentProperty("Header")] + public class RadioButton : System.Windows.Controls.RadioButton, IRibbonControl, IQuickAccessItemProvider + { + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RadioButton)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RadioButton)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RadioButton)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(RadioButton)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RadioButton), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = (RadioButton)d; + + var oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) + { + element.RemoveLogicalChild(oldElement); + } + + var newElement = e.NewValue as FrameworkElement; + if (newElement != null) + { + element.AddLogicalChild(newElement); + } + } + + #endregion + + #region LargeIcon + + /// + /// Gets or sets button large icon + /// + public object LargeIcon + { + get { return this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = DependencyProperty.Register("LargeIcon", typeof(object), typeof(RadioButton), new UIPropertyMetadata(null)); + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RadioButton() + { + var type = typeof(RadioButton); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + ContextMenuService.Attach(type); + ToolTipService.Attach(type); + } + + /// + /// Default constructor + /// + public RadioButton() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + var button = new RadioButton(); + + RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); + button.Click += ((sender, e) => this.RaiseEvent(e)); + RibbonControl.BindQuickAccessItem(this, button); + + return button; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(RadioButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IKeyTipedControl + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.OnClick(); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/Ribbon.cs b/Fluent.Ribbon/Controls/Ribbon.cs similarity index 95% rename from Fluent/Controls/Ribbon.cs rename to Fluent.Ribbon/Controls/Ribbon.cs index 65f17fd28..aaf8a954b 100644 --- a/Fluent/Controls/Ribbon.cs +++ b/Fluent.Ribbon/Controls/Ribbon.cs @@ -1,2238 +1,2293 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.IO.IsolatedStorage; -using System.Linq; -using System.Text; -using System.Threading; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; - -namespace Fluent -{ - using System.ComponentModel; - using System.Windows.Threading; - using Fluent.Extensions; - - // TODO: improve style parts naming & using - - /// - /// Represents the main Ribbon control which consists of multiple tabs, each of which - /// containing groups of controls. The Ribbon also provides improved context - /// menus, enhanced screen tips, and keyboard shortcuts. - /// - [ContentProperty("Tabs")] - [SuppressMessage("Microsoft.Maintainability", "CA1506")] - [SuppressMessage("Microsoft.Design", "CA1001")] - public class Ribbon : Control - { - private readonly RibbonState ribbonState; - - #region Localization - - // Localizable properties - static readonly RibbonLocalization localization = new RibbonLocalization(); - - /// - /// Gets localizable properties - /// - public static RibbonLocalization Localization - { - get { return localization; } - } - - #endregion - - #region Constants - - /// - /// Minimal width of ribbon parent window - /// - public const double MinimalVisibleWidth = 300; - /// - /// Minimal height of ribbon parent window - /// - public const double MinimalVisibleHeight = 250; - - #endregion - - #region ContextMenu - - private static readonly Dictionary contextMenus = new Dictionary(); - - /// - /// Context menu for ribbon in current thread - /// - public static System.Windows.Controls.ContextMenu RibbonContextMenu - { - get - { - if (!contextMenus.ContainsKey(Thread.CurrentThread.ManagedThreadId)) InitRibbonContextMenu(); - return contextMenus[Thread.CurrentThread.ManagedThreadId]; - } - } - - // Context menu owner ribbon - private static Ribbon contextMenuOwner; - - // Context menu items - private static Dictionary addToQuickAccessMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem addToQuickAccessMenuItem - { - get { return addToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary addGroupToQuickAccessMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem addGroupToQuickAccessMenuItem - { - get { return addGroupToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary addMenuToQuickAccessMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem addMenuToQuickAccessMenuItem - { - get { return addMenuToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary addGalleryToQuickAccessMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem addGalleryToQuickAccessMenuItem - { - get { return addGalleryToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary removeFromQuickAccessMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem removeFromQuickAccessMenuItem - { - get { return removeFromQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary showQuickAccessToolbarBelowTheRibbonMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem showQuickAccessToolbarBelowTheRibbonMenuItem - { - get { return showQuickAccessToolbarBelowTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary showQuickAccessToolbarAboveTheRibbonMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem showQuickAccessToolbarAboveTheRibbonMenuItem - { - get { return showQuickAccessToolbarAboveTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary minimizeTheRibbonMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem minimizeTheRibbonMenuItem - { - get { return minimizeTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary customizeQuickAccessToolbarMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem customizeQuickAccessToolbarMenuItem - { - get { return customizeQuickAccessToolbarMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary customizeTheRibbonMenuItemDictionary = new Dictionary(); - private static System.Windows.Controls.MenuItem customizeTheRibbonMenuItem - { - get { return customizeTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary firstSeparatorDictionary = new Dictionary(); - private static Separator firstSeparator - { - get { return firstSeparatorDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - private static Dictionary secondSeparatorDictionary = new Dictionary(); - private static Separator secondSeparator - { - get { return secondSeparatorDictionary[Thread.CurrentThread.ManagedThreadId]; } - } - - // Initialize ribbon context menu - private static void InitRibbonContextMenu() - { - contextMenus.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.ContextMenu()); - RibbonContextMenu.Opened += OnContextMenuOpened; - - // Add to quick access toolbar - addToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); - RibbonContextMenu.Items.Add(addToQuickAccessMenuItem); - RibbonControl.Bind(Localization, addToQuickAccessMenuItem, "RibbonContextMenuAddItem", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, addToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Add group to quick access toolbar - addGroupToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); - RibbonContextMenu.Items.Add(addGroupToQuickAccessMenuItem); - RibbonControl.Bind(Localization, addGroupToQuickAccessMenuItem, "RibbonContextMenuAddGroup", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, addGroupToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Add menu item to quick access toolbar - addMenuToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); - RibbonContextMenu.Items.Add(addMenuToQuickAccessMenuItem); - RibbonControl.Bind(Localization, addMenuToQuickAccessMenuItem, "RibbonContextMenuAddMenu", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, addMenuToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Add gallery to quick access toolbar - addGalleryToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); - RibbonContextMenu.Items.Add(addGalleryToQuickAccessMenuItem); - RibbonControl.Bind(Localization, addGalleryToQuickAccessMenuItem, "RibbonContextMenuAddGallery", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, addGalleryToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Remove from quick access toolbar - removeFromQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = RemoveFromQuickAccessCommand }); - RibbonContextMenu.Items.Add(removeFromQuickAccessMenuItem); - RibbonControl.Bind(Localization, removeFromQuickAccessMenuItem, "RibbonContextMenuRemoveItem", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, removeFromQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Separator - firstSeparatorDictionary.Add(Thread.CurrentThread.ManagedThreadId, new Separator()); - RibbonContextMenu.Items.Add(firstSeparator); - - // Customize quick access toolbar - customizeQuickAccessToolbarMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = CustomizeQuickAccessToolbarCommand }); - RibbonContextMenu.Items.Add(customizeQuickAccessToolbarMenuItem); - RibbonControl.Bind(Localization, customizeQuickAccessToolbarMenuItem, "RibbonContextMenuCustomizeQuickAccessToolBar", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, customizeQuickAccessToolbarMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Show quick access below the ribbon - showQuickAccessToolbarBelowTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ShowQuickAccessBelowCommand }); - RibbonContextMenu.Items.Add(showQuickAccessToolbarBelowTheRibbonMenuItem); - RibbonControl.Bind(Localization, showQuickAccessToolbarBelowTheRibbonMenuItem, "RibbonContextMenuShowBelow", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, showQuickAccessToolbarBelowTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Show quick access above the ribbon - showQuickAccessToolbarAboveTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ShowQuickAccessAboveCommand }); - RibbonContextMenu.Items.Add(showQuickAccessToolbarAboveTheRibbonMenuItem); - RibbonControl.Bind(Localization, showQuickAccessToolbarAboveTheRibbonMenuItem, "RibbonContextMenuShowAbove", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, showQuickAccessToolbarAboveTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Separator - secondSeparatorDictionary.Add(Thread.CurrentThread.ManagedThreadId, new Separator()); - RibbonContextMenu.Items.Add(secondSeparator); - - // Customize the ribbon - customizeTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = CustomizeTheRibbonCommand }); - RibbonContextMenu.Items.Add(customizeTheRibbonMenuItem); - RibbonControl.Bind(Localization, customizeTheRibbonMenuItem, "RibbonContextMenuCustomizeRibbon", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, customizeTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - - // Minimize the ribbon - minimizeTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ToggleMinimizeTheRibbonCommand }); - RibbonContextMenu.Items.Add(minimizeTheRibbonMenuItem); - RibbonControl.Bind(Localization, minimizeTheRibbonMenuItem, "RibbonContextMenuMinimizeRibbon", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - RibbonControl.Bind(RibbonContextMenu, minimizeTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); - } - - /// - /// Invoked whenever an unhandled routed event reaches this class in its route. Implement this method to add class handling for this event. - /// - /// The that contains the event data. - protected override void OnContextMenuOpening(ContextMenuEventArgs e) - { - contextMenuOwner = this; - base.OnContextMenuOpening(e); - } - - /// - /// Invoked whenever an unhandled routed event reaches this class in its route. Implement this method to add class handling for this event. - /// - /// Provides data about the event. - protected override void OnContextMenuClosing(ContextMenuEventArgs e) - { - contextMenuOwner = null; - base.OnContextMenuClosing(e); - } - - // Occurs when context menu is opening - private static void OnContextMenuOpened(object sender, RoutedEventArgs e) - { - var ribbon = contextMenuOwner; - - if (RibbonContextMenu == null - || ribbon == null) - { - return; - } - - addToQuickAccessMenuItem.CommandTarget = ribbon; - addGroupToQuickAccessMenuItem.CommandTarget = ribbon; - addMenuToQuickAccessMenuItem.CommandTarget = ribbon; - addGalleryToQuickAccessMenuItem.CommandTarget = ribbon; - removeFromQuickAccessMenuItem.CommandTarget = ribbon; - customizeQuickAccessToolbarMenuItem.CommandTarget = ribbon; - customizeTheRibbonMenuItem.CommandTarget = ribbon; - minimizeTheRibbonMenuItem.CommandTarget = ribbon; - showQuickAccessToolbarBelowTheRibbonMenuItem.CommandTarget = ribbon; - showQuickAccessToolbarAboveTheRibbonMenuItem.CommandTarget = ribbon; - - // Hide items for ribbon controls - addToQuickAccessMenuItem.Visibility = Visibility.Collapsed; - addGroupToQuickAccessMenuItem.Visibility = Visibility.Collapsed; - addMenuToQuickAccessMenuItem.Visibility = Visibility.Collapsed; - addGalleryToQuickAccessMenuItem.Visibility = Visibility.Collapsed; - removeFromQuickAccessMenuItem.Visibility = Visibility.Collapsed; - firstSeparator.Visibility = Visibility.Collapsed; - - // Hide customize quick access menu item - customizeQuickAccessToolbarMenuItem.Visibility = Visibility.Collapsed; - secondSeparator.Visibility = Visibility.Collapsed; - - // Set minimize the ribbon menu item state - minimizeTheRibbonMenuItem.IsChecked = ribbon.IsMinimized; - - // Set customize the ribbon menu item visibility - if (ribbon.CanCustomizeRibbon) - { - customizeTheRibbonMenuItem.Visibility = Visibility.Visible; - } - else - { - customizeTheRibbonMenuItem.Visibility = Visibility.Collapsed; - } - - // Hide quick access position menu items - showQuickAccessToolbarBelowTheRibbonMenuItem.Visibility = Visibility.Collapsed; - showQuickAccessToolbarAboveTheRibbonMenuItem.Visibility = Visibility.Collapsed; - - // If quick access toolbar is visible show - if (ribbon.IsQuickAccessToolBarVisible) - { - // Set quick access position menu items visibility - if (ribbon.CanQuickAccessLocationChanging) - { - if (ribbon.ShowQuickAccessToolBarAboveRibbon) - { - showQuickAccessToolbarBelowTheRibbonMenuItem.Visibility = Visibility.Visible; - } - else - { - showQuickAccessToolbarAboveTheRibbonMenuItem.Visibility = Visibility.Visible; - } - } - - if (ribbon.CanCustomizeQuickAccessToolBar) - { - customizeQuickAccessToolbarMenuItem.Visibility = Visibility.Visible; - } - - if (ribbon.CanQuickAccessLocationChanging - || ribbon.CanCustomizeQuickAccessToolBar) - { - secondSeparator.Visibility = Visibility.Visible; - } - else - { - secondSeparator.Visibility = Visibility.Collapsed; - } - - if (ribbon.CanCustomizeQuickAccessToolBarItems) - { - // Gets control that raise menu opened - var control = RibbonContextMenu.PlacementTarget; - AddToQuickAccessCommand.CanExecute(null, control); - RemoveFromQuickAccessCommand.CanExecute(null, control); - - //Debug.WriteLine("Menu opened on "+control); - if (control != null) - { - firstSeparator.Visibility = Visibility.Visible; - - // Check for value because remove is only possible in the context menu of items in QA which represent the value for QA-items - if (ribbon.quickAccessElements.ContainsValue(control)) - { - // Control is on quick access - removeFromQuickAccessMenuItem.Visibility = Visibility.Visible; - } - else if (control is System.Windows.Controls.MenuItem) - { - // Control is menu item - addMenuToQuickAccessMenuItem.Visibility = Visibility.Visible; - } - else if ((control is Gallery) || - (control is InRibbonGallery)) - { - // Control is gallery - addGalleryToQuickAccessMenuItem.Visibility = Visibility.Visible; - } - else if (control is RibbonGroupBox) - { - // Control is group box - addGroupToQuickAccessMenuItem.Visibility = Visibility.Visible; - } - else if (control is IQuickAccessItemProvider) - { - // Its other control - addToQuickAccessMenuItem.Visibility = Visibility.Visible; - } - else - { - firstSeparator.Visibility = Visibility.Collapsed; - } - } - } - } - } - - #endregion - - #region Events - - /// - /// Occurs when selected tab has been changed (be aware that SelectedTab can be null) - /// - public event SelectionChangedEventHandler SelectedTabChanged; - - /// - /// Occurs when customize the ribbon - /// - public event EventHandler CustomizeTheRibbon; - - /// - /// Occurs when customize quick access toolbar - /// - public event EventHandler CustomizeQuickAccessToolbar; - - /// - /// Occurs when IsMinimized property is changing - /// - public event DependencyPropertyChangedEventHandler IsMinimizedChanged; - - /// - /// Occurs when IsCollapsed property is changing - /// - public event DependencyPropertyChangedEventHandler IsCollapsedChanged; - - #endregion - - #region Fields - - // Collection of contextual tab groups - private ObservableCollection contextualGroups; - - // Collection of tabs - private ObservableCollection tabs; - - // Collection of toolbar items - private ObservableCollection toolBarItems; - - // Ribbon quick access toolbar - private QuickAccessToolBar quickAccessToolBar; - - // Ribbon layout root - private Panel layoutRoot; - - // Handles F10, Alt and so on - readonly KeyTipService keyTipService; - - // Collection of quickaccess menu items - private ObservableCollection quickAccessItems; - - // Currently added in QAT items - private readonly Dictionary quickAccessElements = new Dictionary(); - - private Window ownerWindow; - - #endregion - - #region Properties - - #region Menu - - /// - /// Gets or sets file menu control (can be application menu button, backstage button and so on) - /// - public UIElement Menu - { - get { return (UIElement)this.GetValue(MenuProperty); } - set { this.SetValue(MenuProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Button. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MenuProperty = - DependencyProperty.Register("Menu", typeof(UIElement), typeof(Ribbon), new UIPropertyMetadata(null, OnApplicationMenuChanged)); - - static void OnApplicationMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - Ribbon ribbon = (Ribbon)d; - if (e.OldValue != null) ribbon.RemoveLogicalChild(e.OldValue); - if (e.NewValue != null) ribbon.AddLogicalChild(e.NewValue); - } - - #endregion - - /// - /// Window title - /// - public string Title - { - get { return (string)this.GetValue(TitleProperty); } - set { this.SetValue(TitleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(Ribbon), new UIPropertyMetadata("", OnTitleChanged)); - - private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = d as Ribbon; - - if (ribbon != null - && ribbon.TitleBar != null) - { - ribbon.TitleBar.InvalidateMeasure(); - } - } - - /// - /// Gets or sets selected tab item - /// - public RibbonTabItem SelectedTabItem - { - get { return (RibbonTabItem)this.GetValue(SelectedTabItemProperty); } - set { this.SetValue(SelectedTabItemProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectedTabItem. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedTabItemProperty = - DependencyProperty.Register("SelectedTabItem", typeof(RibbonTabItem), typeof(Ribbon), new UIPropertyMetadata(null, OnSelectedTabItemChanged)); - - private static void OnSelectedTabItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - if (ribbon.TabControl != null) - { - ribbon.TabControl.SelectedItem = e.NewValue; - } - - var selectedItem = e.NewValue as RibbonTabItem; - - if (selectedItem != null - && ribbon.Tabs.Contains(selectedItem)) - { - ribbon.SelectedTabIndex = ribbon.Tabs.IndexOf(selectedItem); - } - else - { - ribbon.SelectedTabIndex = -1; - } - } - - /// - /// Gets or sets selected tab index - /// - public int SelectedTabIndex - { - get { return (int)this.GetValue(SelectedTabIndexProperty); } - set { this.SetValue(SelectedTabIndexProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectedTabindex. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedTabIndexProperty = - DependencyProperty.Register("SelectedTabIndex", typeof(int), typeof(Ribbon), new UIPropertyMetadata(-1, OnSelectedTabIndexChanged)); - - private static void OnSelectedTabIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - var selectedIndex = (int)e.NewValue; - - if (ribbon.TabControl != null) - { - ribbon.TabControl.SelectedIndex = selectedIndex; - } - - if (selectedIndex >= 0 - && selectedIndex < ribbon.Tabs.Count) - { - ribbon.SelectedTabItem = ribbon.Tabs[selectedIndex]; - } - else - { - ribbon.SelectedTabItem = null; - } - } - - /// - /// Gets the first visible TabItem - /// - public RibbonTabItem FirstVisibleItem - { - get - { - return this.GetFirstVisibleItem(); - } - } - - /// - /// Gets the last visible TabItem - /// - public RibbonTabItem LastVisibleItem - { - get - { - return this.GetLastVisibleItem(); - } - } - - /// - /// Gets the list of currently active quick access elements. - /// - protected Dictionary QuickAccessElements - { - get - { - return this.quickAccessElements; - } - } - - /// - /// Gets ribbon titlebar - /// - internal RibbonTitleBar TitleBar { get; private set; } - - /// - /// Gets the Ribbon tab control - /// - internal RibbonTabControl TabControl { get; private set; } - - /// - /// Gets or sets whether quick access toolbar showes above ribbon - /// - public bool ShowQuickAccessToolBarAboveRibbon - { - get { return (bool)this.GetValue(ShowQuickAccessToolBarAboveRibbonProperty); } - set { this.SetValue(ShowQuickAccessToolBarAboveRibbonProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ShowAboveRibbon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ShowQuickAccessToolBarAboveRibbonProperty = - DependencyProperty.Register("ShowQuickAccessToolBarAboveRibbon", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true, OnShowQuickAccesToolBarAboveRibbonChanged)); - - /// - /// Handles ShowQuickAccessToolBarAboveRibbon property changed - /// - /// Object - /// The event data - private static void OnShowQuickAccesToolBarAboveRibbonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - if (ribbon.TitleBar != null) - { - ribbon.TitleBar.InvalidateMeasure(); - } - - ribbon.ribbonState.SaveStateToMemoryStream(); - } - - /// - /// Gets collection of contextual tab groups - /// - public ObservableCollection ContextualGroups - { - get - { - if (this.contextualGroups == null) - { - this.contextualGroups = new ObservableCollection(); - this.contextualGroups.CollectionChanged += this.OnContextualGroupsCollectionChanged; - } - - return this.contextualGroups; - } - } - - /// - /// Handles collection of contextual tab groups ghanges - /// - /// Sender - /// The event data - private void OnContextualGroupsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (int i = 0; i < e.NewItems.Count; i++) - { - if (this.TitleBar != null) this.TitleBar.Items.Insert(e.NewStartingIndex + i, e.NewItems[i]); - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (object item in e.OldItems) - { - if (this.TitleBar != null) this.TitleBar.Items.Remove(item); - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (object item in e.OldItems) - { - if (this.TitleBar != null) this.TitleBar.Items.Remove(item); - } - foreach (object item in e.NewItems) - { - if (this.TitleBar != null) this.TitleBar.Items.Add(item); - } - break; - case NotifyCollectionChangedAction.Reset: - if (this.TitleBar != null) this.TitleBar.Items.Clear(); - break; - } - - } - - /// - /// gets collection of ribbon tabs - /// - public ObservableCollection Tabs - { - get - { - if (this.tabs == null) - { - this.tabs = new ObservableCollection(); - this.tabs.CollectionChanged += this.OnTabsCollectionChanged; - } - - return this.tabs; - } - } - - /// - /// Handles collection of ribbon tabs changed - /// - /// Sender - /// The event data - private void OnTabsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (this.TabControl == null) - { - return; - } - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (var i = 0; i < e.NewItems.Count; i++) - { - this.TabControl.Items.Insert(e.NewStartingIndex + i, e.NewItems[i]); - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (var item in e.OldItems) - { - this.TabControl.Items.Remove(item); - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var item in e.OldItems) - { - this.TabControl.Items.Remove(item); - } - - foreach (var item in e.NewItems) - { - this.TabControl.Items.Add(item); - } - break; - - case NotifyCollectionChangedAction.Reset: - this.TabControl.Items.Clear(); - break; - } - } - - /// - /// Gets collection of toolbar items - /// - public ObservableCollection ToolBarItems - { - get - { - if (this.toolBarItems == null) - { - this.toolBarItems = new ObservableCollection(); - this.toolBarItems.CollectionChanged += this.OnToolbarItemsCollectionChanged; - } - - return this.toolBarItems; - } - } - - /// - /// Handles collection of toolbar items changes - /// - /// Sender - /// The event data - private void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (int i = 0; i < e.NewItems.Count; i++) - { - if (this.TabControl != null) - this.TabControl.ToolBarItems.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (object item in e.OldItems) - { - if (this.TabControl != null) - this.TabControl.ToolBarItems.Remove(item as UIElement); - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (object item in e.OldItems) - { - if (this.TabControl != null) - this.TabControl.ToolBarItems.Remove(item as UIElement); - } - foreach (object item in e.NewItems) - { - if (this.TabControl != null) - this.TabControl.ToolBarItems.Add(item as UIElement); - } - break; - } - - } - - /// - /// Gets quick access toolbar associated with the ribbon - /// - internal QuickAccessToolBar QuickAccessToolBar - { - get { return this.quickAccessToolBar; } - } - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - if (this.layoutRoot != null) - { - yield return this.layoutRoot; - } - - if (this.Menu != null) - { - yield return this.Menu; - } - - if (this.quickAccessToolBar != null) - { - yield return this.quickAccessToolBar; - } - - if (this.TabControl != null - && this.TabControl.ToolbarPanel != null) - { - yield return this.TabControl.ToolbarPanel; - } - } - } - - /// - /// Gets collection of quick access menu items - /// - public ObservableCollection QuickAccessItems - { - get - { - if (this.quickAccessItems == null) - { - this.quickAccessItems = new ObservableCollection(); - this.quickAccessItems.CollectionChanged += this.OnQuickAccessItemsCollectionChanged; - } - - return this.quickAccessItems; - } - } - - /// - /// Handles collection of quick access menu items changes - /// - /// Sender - /// The event data - private void OnQuickAccessItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (var i = 0; i < e.NewItems.Count; i++) - { - var menuItem = (QuickAccessMenuItem)e.NewItems[i]; - if (this.quickAccessToolBar != null) - { - this.quickAccessToolBar.QuickAccessItems.Insert(e.NewStartingIndex + i, menuItem); - } - menuItem.Ribbon = this; - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (var item in e.OldItems.OfType()) - { - var menuItem = item; - if (this.quickAccessToolBar != null) - { - this.quickAccessToolBar.QuickAccessItems.Remove(menuItem); - } - menuItem.Ribbon = null; - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var item in e.OldItems.OfType()) - { - var menuItem = item; - if (this.quickAccessToolBar != null) - { - this.quickAccessToolBar.QuickAccessItems.Remove(menuItem); - } - menuItem.Ribbon = null; - } - foreach (var item in e.NewItems.OfType()) - { - var menuItem = item; - if (this.quickAccessToolBar != null) - { - this.quickAccessToolBar.QuickAccessItems.Add(menuItem); - } - menuItem.Ribbon = this; - } - break; - } - } - - /// - /// Gets or sets whether Customize Quick Access Toolbar menu item is shown - /// - public bool CanCustomizeQuickAccessToolBar - { - get { return (bool)this.GetValue(CanCustomizeQuickAccessToolBarProperty); } - set { this.SetValue(CanCustomizeQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanCustomizeQuickAccessToolBar. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanCustomizeQuickAccessToolBarProperty = - DependencyProperty.Register("CanCustomizeQuickAccessToolBar", typeof(bool), - typeof(Ribbon), new UIPropertyMetadata(false)); - - /// - /// Gets or sets whether items can be added or removed from the quick access toolbar by users. - /// - public bool CanCustomizeQuickAccessToolBarItems - { - get { return (bool)this.GetValue(CanCustomizeQuickAccessToolBarItemsProperty); } - set { this.SetValue(CanCustomizeQuickAccessToolBarItemsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanCustomizeQuickAccessToolBarItems. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanCustomizeQuickAccessToolBarItemsProperty = - DependencyProperty.Register("CanCustomizeQuickAccessToolBarItems", typeof(bool), typeof(Ribbon), new PropertyMetadata(true)); - - /// - /// Gets or sets whether Customize Ribbon menu item is shown - /// - public bool CanCustomizeRibbon - { - get { return (bool)this.GetValue(CanCustomizeRibbonProperty); } - set { this.SetValue(CanCustomizeRibbonProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanCustomizeRibbon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanCustomizeRibbonProperty = - DependencyProperty.Register("CanCustomizeRibbon", typeof(bool), - typeof(Ribbon), new UIPropertyMetadata(false)); - - - /// - /// Gets or sets whether ribbon is minimized - /// - public bool IsMinimized - { - get { return (bool)this.GetValue(IsMinimizedProperty); } - set { this.SetValue(IsMinimizedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsMinimized. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsMinimizedProperty = - DependencyProperty.Register("IsMinimized", typeof(bool), - typeof(Ribbon), new UIPropertyMetadata(false, OnIsMinimizedChanged)); - - private static void OnIsMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - - if (ribbon.IsMinimizedChanged != null) - { - ribbon.IsMinimizedChanged(ribbon, e); - } - } - - /// - /// Gets or sets the height of the gap between the ribbon and the content - /// - public double ContentGapHeight - { - get { return (double)this.GetValue(ContentGapHeightProperty); } - set { this.SetValue(ContentGapHeightProperty, value); } - } - - /// - /// DependencyProperty for - /// - public static readonly DependencyProperty ContentGapHeightProperty = - DependencyProperty.Register("ContentGapHeight", typeof(double), typeof(Ribbon), new UIPropertyMetadata(5D)); - - // todo check if IsCollapsed and IsAutomaticCollapseEnabled should be reduced to one shared property for RibbonWindow and Ribbon - /// - /// Gets whether ribbon is collapsed - /// - public bool IsCollapsed - { - get { return (bool)this.GetValue(IsCollapsedProperty); } - set { this.SetValue(IsCollapsedProperty, value); } - } - - /// - /// DependencyProperty for - /// - public static readonly DependencyProperty IsCollapsedProperty = - DependencyProperty.Register("IsCollapsed", typeof(bool), - typeof(Ribbon), new FrameworkPropertyMetadata(false, OnIsCollapsedChanged)); - - private static void OnIsCollapsedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - if (ribbon.IsCollapsedChanged != null) - { - ribbon.IsCollapsedChanged(ribbon, e); - } - } - - /// - /// Defines if the Ribbon should automatically set when the width or height of the owner window drop under or - /// - public bool IsAutomaticCollapseEnabled - { - get { return (bool)this.GetValue(IsAutomaticCollapseEnabledProperty); } - set { this.SetValue(IsAutomaticCollapseEnabledProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsCollapsed. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsAutomaticCollapseEnabledProperty = - DependencyProperty.Register("IsAutomaticCollapseEnabled", typeof(bool), typeof(Ribbon), new PropertyMetadata(true)); - - /// - /// Gets or sets whether QAT is visible - /// - public bool IsQuickAccessToolBarVisible - { - get { return (bool)this.GetValue(IsQuickAccessToolBarVisibleProperty); } - set { this.SetValue(IsQuickAccessToolBarVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsQuickAccessToolBarVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsQuickAccessToolBarVisibleProperty = - DependencyProperty.Register("IsQuickAccessToolBarVisible", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true)); - - - /// - /// Gets or sets whether user can change location of QAT - /// - public bool CanQuickAccessLocationChanging - { - get { return (bool)this.GetValue(CanQuickAccessLocationChangingProperty); } - set { this.SetValue(CanQuickAccessLocationChangingProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanQuickAccessLocationChanging. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanQuickAccessLocationChangingProperty = - DependencyProperty.Register("CanQuickAccessLocationChanging", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true)); - - - /// - /// Checks if any keytips are visible. - /// - public bool AreAnyKeyTipsVisible - { - get - { - if (this.keyTipService != null) - { - return this.keyTipService.AreAnyKeyTipsVisible; - } - - return false; - } - } - #endregion - - #region Commands - - /// - /// Gets add to quick access toolbar command - /// - public static RoutedCommand AddToQuickAccessCommand = new RoutedCommand("AddToQuickAccessCommand", typeof(Ribbon)); - - /// - /// Gets remove from quick access command - /// - public static RoutedCommand RemoveFromQuickAccessCommand = new RoutedCommand("RemoveFromQuickAccessCommand", typeof(Ribbon)); - - /// - /// Gets show quick access above command - /// - public static RoutedCommand ShowQuickAccessAboveCommand = new RoutedCommand("ShowQuickAccessAboveCommand", typeof(Ribbon)); - - /// - /// Gets show quick access below command - /// - public static RoutedCommand ShowQuickAccessBelowCommand = new RoutedCommand("ShowQuickAccessBelowCommand", typeof(Ribbon)); - - /// - /// Gets toggle ribbon minimize command - /// - public static RoutedCommand ToggleMinimizeTheRibbonCommand = new RoutedCommand("ToggleMinimizeTheRibbonCommand", typeof(Ribbon)); - - /// - /// Gets customize quick access toolbar command - /// - public static RoutedCommand CustomizeQuickAccessToolbarCommand = new RoutedCommand("CustomizeQuickAccessToolbarCommand", typeof(Ribbon)); - - /// - /// Gets customize the ribbon command - /// - public static RoutedCommand CustomizeTheRibbonCommand = new RoutedCommand("CustomizeTheRibbonCommand", typeof(Ribbon)); - - // Occurs when customize toggle minimize command can execute handles - private static void OnToggleMinimizeTheRibbonCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon != null - && ribbon.TabControl != null) - { - e.CanExecute = true; - } - } - - // Occurs when toggle minimize command executed - private static void OnToggleMinimizeTheRibbonCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - if (ribbon != null - && ribbon.TabControl != null) - { - ribbon.TabControl.IsMinimized = !ribbon.TabControl.IsMinimized; - } - } - - // Occurs when show quick access below command executed - private static void OnShowQuickAccessBelowCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - ribbon.ShowQuickAccessToolBarAboveRibbon = false; - } - - // Occurs when show quick access above command executed - private static void OnShowQuickAccessAboveCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - ribbon.ShowQuickAccessToolBarAboveRibbon = true; - } - - // Occurs when remove from quick access command executed - private static void OnRemoveFromQuickAccessCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - if (ribbon.quickAccessToolBar != null) - { - var element = ribbon.quickAccessElements.First(x => x.Value == e.Parameter).Key; - ribbon.RemoveFromQuickAccessToolBar(element); - } - } - - // Occurs when add to quick access command executed - private static void OnAddToQuickAccessCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - if (ribbon.quickAccessToolBar != null) - { - ribbon.AddToQuickAccessToolBar(e.Parameter as UIElement); - } - } - - // Occurs when customize quick access command executed - private static void OnCustomizeQuickAccessToolbarCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - if (ribbon.CustomizeQuickAccessToolbar != null) - { - ribbon.CustomizeQuickAccessToolbar(sender, EventArgs.Empty); - } - } - - // Occurs when customize the ribbon command executed - private static void OnCustomizeTheRibbonCommandExecuted(object sender, ExecutedRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - if (ribbon.CustomizeTheRibbon != null) - { - ribbon.CustomizeTheRibbon(sender, EventArgs.Empty); - } - } - - // Occurs when customize quick access command can execute handles - private static void OnCustomizeQuickAccessToolbarCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - e.CanExecute = ribbon.CanCustomizeQuickAccessToolBar; - } - - // Occurs when customize the ribbon command can execute handles - private static void OnCustomizeTheRibbonCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - e.CanExecute = ribbon.CanCustomizeRibbon; - } - - // Occurs when remove from quick access command can execute handles - private static void OnRemoveFromQuickAccessCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon == null) - { - return; - } - - if (ribbon.IsQuickAccessToolBarVisible) - { - e.CanExecute = ribbon.quickAccessElements.ContainsValue(e.Parameter as UIElement); - } - else - { - e.CanExecute = false; - } - } - - // Occurs when add to quick access command can execute handles - private static void OnAddToQuickAccessCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) - { - var ribbon = sender as Ribbon; - - if (ribbon != null - && ribbon.IsQuickAccessToolBarVisible - && QuickAccessItemsProvider.IsSupported(e.Parameter as UIElement) - && ribbon.IsInQuickAccessToolBar(e.Parameter as UIElement) == false) - { - if (e.Parameter is Gallery) - { - e.CanExecute = ribbon.IsInQuickAccessToolBar(FindParentRibbonControl(e.Parameter as DependencyObject) as UIElement) == false; - } - else - { - e.CanExecute = ribbon.IsInQuickAccessToolBar(e.Parameter as UIElement) == false; - } - } - else - { - e.CanExecute = false; - } - } - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static Ribbon() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Ribbon), new FrameworkPropertyMetadata(typeof(Ribbon))); - - // Subscribe to menu commands - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(AddToQuickAccessCommand, OnAddToQuickAccessCommandExecuted, OnAddToQuickAccessCommandCanExecute)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(RemoveFromQuickAccessCommand, OnRemoveFromQuickAccessCommandExecuted, OnRemoveFromQuickAccessCommandCanExecute)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ShowQuickAccessAboveCommand, OnShowQuickAccessAboveCommandExecuted)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ShowQuickAccessBelowCommand, OnShowQuickAccessBelowCommandExecuted)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ToggleMinimizeTheRibbonCommand, OnToggleMinimizeTheRibbonCommandExecuted, OnToggleMinimizeTheRibbonCommandCanExecute)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(CustomizeTheRibbonCommand, OnCustomizeTheRibbonCommandExecuted, OnCustomizeTheRibbonCommandCanExecute)); - CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(CustomizeQuickAccessToolbarCommand, OnCustomizeQuickAccessToolbarCommandExecuted, OnCustomizeQuickAccessToolbarCommandCanExecute)); - - InitRibbonContextMenu(); - } - - /// - /// Default constructor - /// - public Ribbon() - { - this.VerticalAlignment = VerticalAlignment.Top; - KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Contained); - - this.keyTipService = new KeyTipService(this); - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - - this.ribbonState = new RibbonState(this); - } - - #endregion - - #region Overrides - - private void OnSizeChanged(object sender, SizeChangedEventArgs e) - { - this.MaintainIsCollapsed(); - } - - private void MaintainIsCollapsed() - { - if (this.IsAutomaticCollapseEnabled == false - || this.ownerWindow == null) - { - return; - } - - if (this.ownerWindow.ActualWidth < MinimalVisibleWidth - || this.ownerWindow.ActualHeight < MinimalVisibleHeight) - { - this.IsCollapsed = true; - } - else - { - this.IsCollapsed = false; - } - } - - /// - /// Invoked whenever an unhandled System.Windows.UIElement.GotFocus - /// event reaches this element in its route. - /// - /// The System.Windows.RoutedEventArgs that contains the event data. - protected override void OnGotFocus(RoutedEventArgs e) - { - if (this.TabControl == null) - { - return; - } - - var ribbonTabItem = (RibbonTabItem)this.TabControl.SelectedItem; - if (ribbonTabItem != null) - { - ribbonTabItem.Focus(); - } - } - - /// - /// When overridden in a derived class, is invoked whenever application code or - /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - public override void OnApplyTemplate() - { - if (this.layoutRoot != null) - { - this.RemoveLogicalChild(this.layoutRoot); - } - - this.layoutRoot = this.GetTemplateChild("PART_LayoutRoot") as Panel; - - if (this.layoutRoot != null) - { - this.AddLogicalChild(this.layoutRoot); - } - - if (this.TitleBar != null) - { - foreach (var ribbonContextualTabGroup in this.ContextualGroups) - { - this.TitleBar.Items.Remove(ribbonContextualTabGroup); - } - - // Make sure everything is cleared - this.TitleBar.Items.Clear(); - } - - this.TitleBar = this.GetTemplateChild("PART_RibbonTitleBar") as RibbonTitleBar; - - if (this.TitleBar != null) - { - foreach (var contextualTabGroup in this.ContextualGroups) - { - this.TitleBar.Items.Add(contextualTabGroup); - } - } - - var selectedTab = this.SelectedTabItem; - if (this.TabControl != null) - { - this.TabControl.SelectionChanged -= this.OnTabControlSelectionChanged; - selectedTab = this.TabControl.SelectedItem as RibbonTabItem; - - foreach (var ribbonTabItem in this.Tabs) - { - this.TabControl.Items.Remove(ribbonTabItem); - } - - // Make sure everything is cleared - this.TabControl.Items.Clear(); - - foreach (var toolBarItem in this.ToolBarItems) - { - this.TabControl.ToolBarItems.Remove(toolBarItem); - } - - // Make sure everything is cleared - this.TabControl.ToolBarItems.Clear(); - } - - this.TabControl = this.GetTemplateChild("PART_RibbonTabControl") as RibbonTabControl; - - if (this.TabControl != null) - { - this.TabControl.SelectionChanged += this.OnTabControlSelectionChanged; - - this.TabControl.IsMinimized = this.IsMinimized; - this.TabControl.ContentGapHeight = this.ContentGapHeight; - - this.TabControl.SetBinding(RibbonTabControl.IsMinimizedProperty, new Binding("IsMinimized") { Source = this, Mode = BindingMode.TwoWay }); - this.TabControl.SetBinding(RibbonTabControl.ContentGapHeightProperty, new Binding("ContentGapHeight") { Source = this, Mode = BindingMode.OneWay }); - - foreach (var ribbonTabItem in this.Tabs) - { - this.TabControl.Items.Add(ribbonTabItem); - } - - this.TabControl.SelectedItem = selectedTab; - - foreach (var toolBarItem in this.ToolBarItems) - { - this.TabControl.ToolBarItems.Add(toolBarItem); - } - } - - if (this.quickAccessToolBar != null) - { - if (this.AutomaticStateManagement == false - || this.ribbonState.IsStateLoaded) - { - this.ribbonState.SaveStateToMemoryStream(); - } - - this.ClearQuickAccessToolBar(); - - this.quickAccessToolBar.ItemsChanged -= this.OnQuickAccessItemsChanged; - - foreach (var quickAccessMenuItem in this.QuickAccessItems) - { - this.quickAccessToolBar.QuickAccessItems.Remove(quickAccessMenuItem); - } - } - - this.quickAccessToolBar = this.GetTemplateChild("PART_QuickAccessToolBar") as QuickAccessToolBar; - - if (this.quickAccessToolBar != null) - { - foreach (var quickAccessMenuItem in this.QuickAccessItems) - { - this.quickAccessToolBar.QuickAccessItems.Add(quickAccessMenuItem); - } - - this.quickAccessToolBar.ItemsChanged += this.OnQuickAccessItemsChanged; - - var binding = new Binding("CanQuickAccessLocationChanging") - { - Source = this, - Mode = BindingMode.OneWay - }; - this.quickAccessToolBar.SetBinding(QuickAccessToolBar.CanQuickAccessLocationChangingProperty, binding); - - if (this.quickAccessToolBar.Parent == null) - { - this.AddLogicalChild(this.quickAccessToolBar); - } - - this.quickAccessToolBar.Loaded += this.OnFirstToolbarLoaded; - } - } - - /// - /// Called when the is closed, so that we set it to null and clear the - /// - private void OnOwnerWindowClosed(object sender, EventArgs e) - { - this.DetachFromWindow(); - } - - private void AttachToWindow() - { - this.DetachFromWindow(); - - this.ownerWindow = Window.GetWindow(this); - - if (this.ownerWindow != null) - { - this.ownerWindow.Closed += this.OnOwnerWindowClosed; - this.ownerWindow.SizeChanged += this.OnSizeChanged; - this.ownerWindow.KeyDown += this.OnKeyDown; - - var binding = new Binding("Title") - { - Mode = BindingMode.OneWay, - Source = this.ownerWindow - }; - this.SetBinding(TitleProperty, binding); - } - } - - private void DetachFromWindow() - { - if (this.ownerWindow != null) - { - this.ribbonState.SaveStateToIsolatedStorage(); - - this.ownerWindow.Closed -= this.OnOwnerWindowClosed; - this.ownerWindow.SizeChanged -= this.OnSizeChanged; - this.ownerWindow.KeyDown -= this.OnKeyDown; - - BindingOperations.ClearBinding(this, TitleProperty); - } - - this.ownerWindow = null; - } - - private void OnFirstToolbarLoaded(object sender, RoutedEventArgs e) - { - this.quickAccessToolBar.Loaded -= this.OnFirstToolbarLoaded; - - this.ribbonState.LoadStateFromMemoryStream(); - } - - #endregion - - #region Quick Access Items Managment - - /// - /// Determines whether the given element is in quick access toolbar - /// - /// Element - /// True if element in quick access toolbar - public bool IsInQuickAccessToolBar(UIElement element) - { - if (element == null) - { - return false; - } - - return this.quickAccessElements.ContainsKey(element); - } - - /// - /// Adds the given element to quick access toolbar - /// - /// Element - public void AddToQuickAccessToolBar(UIElement element) - { - if (element == null) - { - return; - } - - if (element is Gallery) - { - element = FindParentRibbonControl(element) as UIElement; - } - - // Do not add menu items without icon. - var menuItem = element as MenuItem; - if (menuItem != null && menuItem.Icon == null) - { - element = FindParentRibbonControl(element) as UIElement; - } - - if (element == null) - { - return; - } - - if (QuickAccessItemsProvider.IsSupported(element) == false) - { - return; - } - - if (this.IsInQuickAccessToolBar(element) == false) - { - Debug.WriteLine("Adding \"{0}\" to QuickAccessToolBar.", element); - - var control = QuickAccessItemsProvider.GetQuickAccessItem(element); - - this.quickAccessElements.Add(element, control); - this.quickAccessToolBar.Items.Add(control); - } - } - - private static IRibbonControl FindParentRibbonControl(DependencyObject element) - { - var parent = LogicalTreeHelper.GetParent(element); - - while (parent != null) - { - var control = parent as IRibbonControl; - if (control != null) - { - return control; - } - - parent = LogicalTreeHelper.GetParent(parent); - } - - return null; - } - - /// - /// Removes the given elements from quick access toolbar - /// - /// Element - public void RemoveFromQuickAccessToolBar(UIElement element) - { - Debug.WriteLine("Removing \"{0}\" from QuickAccessToolBar.", element); - - if (this.IsInQuickAccessToolBar(element)) - { - var quickAccessItem = this.quickAccessElements[element]; - this.quickAccessElements.Remove(element); - this.quickAccessToolBar.Items.Remove(quickAccessItem); - } - } - - /// - /// Clears quick access toolbar - /// - public void ClearQuickAccessToolBar() - { - this.quickAccessElements.Clear(); - if (this.quickAccessToolBar != null) - { - this.quickAccessToolBar.Items.Clear(); - } - } - - #endregion - - #region Event Handling - - // Handles tab control selection changed - private void OnTabControlSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (this.TabControl != null) - { - this.SelectedTabItem = this.TabControl.SelectedItem as RibbonTabItem; - this.SelectedTabIndex = this.TabControl.SelectedIndex; - } - - if (this.SelectedTabChanged != null) - { - this.SelectedTabChanged(this, e); - } - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.keyTipService.Attach(); - - this.AttachToWindow(); - - this.LoadInitialState(); - } - - private void OnKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.F1 - && Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) - { - if (this.TabControl.HasItems) - { - this.IsMinimized = !this.IsMinimized; - } - } - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.ribbonState.SaveStateToIsolatedStorage(); - - this.keyTipService.Detach(); - - if (this.ownerWindow != null) - { - this.ownerWindow.SizeChanged -= this.OnSizeChanged; - this.ownerWindow.KeyDown -= this.OnKeyDown; - } - } - - #endregion - - #region Private methods - - private RibbonTabItem GetFirstVisibleItem() - { - return this.Tabs.FirstOrDefault(item => item.Visibility == Visibility.Visible); - } - - private RibbonTabItem GetLastVisibleItem() - { - return this.Tabs.LastOrDefault(item => item.Visibility == Visibility.Visible); - } - - #endregion - - #region State Management - - private void LoadInitialState() - { - if (this.ribbonState.IsStateLoaded) - { - return; - } - - this.ribbonState.LoadStateFromIsolatedStorage(); - - if (this.TabControl != null - && this.TabControl.SelectedIndex == -1 - && this.TabControl.IsMinimized == false) - { - this.TabControl.SelectedIndex = 0; - } - } - - // Handles items changing in QAT - private void OnQuickAccessItemsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.ribbonState.SaveStateToMemoryStream(); - } - - // Traverse logical tree and find QAT items, remember paths - private void TraverseLogicalTree(DependencyObject item, string path, IDictionary paths) - { - // Is this item in QAT - var uielement = item as FrameworkElement; - if (uielement != null - && this.quickAccessElements.ContainsKey(uielement)) - { - if (!paths.ContainsKey(uielement)) - { - paths.Add(uielement, path); - } - } - - var children = LogicalTreeHelper.GetChildren(item).Cast().ToArray(); - for (var i = 0; i < children.Length; i++) - { - var child = children[i] as DependencyObject; - if (child == null) - { - continue; - } - - this.TraverseLogicalTree(child, path + i + ",", paths); - } - } - - #endregion - - #region Load from Stream - - // Loads item and add to QAT - private void ParseAndAddToQuickAccessToolBar(string data) - { - var indices = data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) - .Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray(); - - DependencyObject current = this; - - for (var i = 0; i < indices.Length; i++) - { - var children = LogicalTreeHelper.GetChildren(current).OfType().ToArray(); - var indexIsInvalid = children.Length <= indices[i]; - var item = indexIsInvalid - ? null - : children[indices[i]] as DependencyObject; - - if (item == null) - { - // Path is incorrect - Debug.WriteLine("Error while QAT items loading: one of the paths is invalid"); - return; - } - - current = item; - } - - var result = current as UIElement; - if (result == null - || QuickAccessItemsProvider.IsSupported(result) == false) - { - // Item is invalid - Debug.WriteLine("Error while QAT items loading. Could not add \"{0}\" to QAT.", current); - return; - } - - this.AddToQuickAccessToolBar(result); - } - - #endregion - - #region AutomaticStateManagement Property - - // To temporary suppress automatic management - private bool suppressAutomaticStateManagement; - - /// - /// Gets or sets whether Quick Access ToolBar can - /// save and load its state automatically - /// - public bool AutomaticStateManagement - { - get { return (bool)this.GetValue(AutomaticStateManagementProperty); } - set { this.SetValue(AutomaticStateManagementProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for AutomaticStateManagement. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty AutomaticStateManagementProperty = - DependencyProperty.Register("AutomaticStateManagement", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true, OnAutoStateManagement, CoerceAutoStateManagement)); - - private static object CoerceAutoStateManagement(DependencyObject d, object basevalue) - { - var ribbon = (Ribbon)d; - if (ribbon.suppressAutomaticStateManagement) - { - return false; - } - - return basevalue; - } - - private static void OnAutoStateManagement(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (Ribbon)d; - if ((bool)e.NewValue) - { - ribbon.LoadInitialState(); - } - } - - #endregion - - private class RibbonState : IDisposable - { - private readonly Ribbon ribbon; - - // Name of the isolated storage file - private string isolatedStorageFileName; - private Stream memoryStream; - - public RibbonState(Ribbon ribbon) - { - this.ribbon = ribbon; - this.memoryStream = new MemoryStream(); - } - - /// - /// Gets or sets whether state is loaded - /// - public bool IsStateLoaded { get; private set; } - - /// - /// Gets name of the isolated storage file - /// - private string IsolatedStorageFileName - { - get - { - if (this.isolatedStorageFileName != null) - { - return this.isolatedStorageFileName; - } - - var stringForHash = ""; - var window = Window.GetWindow(this.ribbon); - - if (window != null) - { - stringForHash += "." + window.GetType().FullName; - - if (string.IsNullOrEmpty(window.Name) == false - && window.Name.Trim().Length > 0) - { - stringForHash += "." + window.Name; - } - } - - if (string.IsNullOrEmpty(this.ribbon.Name) == false - && this.ribbon.Name.Trim().Length > 0) - { - stringForHash += "." + this.ribbon.Name; - } - - this.isolatedStorageFileName = "Fluent.Ribbon.State.2.0." + stringForHash.GetHashCode().ToString("X"); - return this.isolatedStorageFileName; - } - } - - public void SaveStateToMemoryStream() - { - this.memoryStream.Position = 0; - this.SaveState(this.memoryStream); - } - - // Saves to Isolated Storage (in user store for domain) - public void SaveStateToIsolatedStorage() - { - // Check whether automatic save is valid now - if (this.ribbon.AutomaticStateManagement == false) - { - Trace.WriteLine(string.Format("State not saved to isolated storage. Because automatic state management is disabled.")); - return; - } - - if (this.IsStateLoaded == false) - { - Trace.WriteLine(string.Format("State not saved to isolated storage. Because state was not loaded before.")); - return; - } - - try - { - var storage = GetIsolatedStorageFile(); - - using (var stream = new IsolatedStorageFileStream(this.IsolatedStorageFileName, FileMode.Create, FileAccess.Write, storage)) - { - this.SaveState(stream); - } - } - catch (Exception ex) - { - Trace.WriteLine(string.Format("Error while trying to save Ribbon state. Error: {0}", ex)); - } - } - - /// - /// Saves state to the given stream - /// - /// Stream - private void SaveState(Stream stream) - { - // Don't save or load state in design mode - if (DesignerProperties.GetIsInDesignMode(this.ribbon)) - { - return; - } - - var builder = new StringBuilder(); - - var isMinimizedSaveState = this.ribbon.IsMinimized; - - // Save Ribbon State - builder.Append(isMinimizedSaveState.ToString(CultureInfo.InvariantCulture)); - builder.Append(','); - builder.Append(this.ribbon.ShowQuickAccessToolBarAboveRibbon.ToString(CultureInfo.InvariantCulture)); - builder.Append('|'); - - // Save QAT items - var paths = new Dictionary(); - this.ribbon.TraverseLogicalTree(this.ribbon, "", paths); - - // Foreach items and see whether path is found for the item - foreach (var element in this.ribbon.quickAccessElements) - { - string path; - var control = element.Key as FrameworkElement; - - if (control != null - && paths.TryGetValue(control, out path)) - { - builder.Append(path); - builder.Append(';'); - } - else - { - // Item is not found in logical tree, output to debug console - var controlName = (control != null && string.IsNullOrEmpty(control.Name) == false) - ? string.Format(CultureInfo.InvariantCulture, " (name of the control is {0})", control.Name) - : string.Empty; - - Debug.WriteLine("Control " + element.Key.GetType().Name + " is not found in logical tree during QAT saving" + controlName); - } - } - - var writer = new StreamWriter(stream); - writer.Write(builder.ToString()); - - writer.Flush(); - } - - public void LoadStateFromMemoryStream() - { - this.memoryStream.Position = 0; - this.LoadState(this.memoryStream); - } - - /// - /// Loads the State from Isolated Storage (in user store for domain) - /// - /// - /// Sets after it's finished to prevent a race condition with saving the state to the MemoryStream. - /// - public void LoadStateFromIsolatedStorage() - { - // Don't save or load state in design mode - if (DesignerProperties.GetIsInDesignMode(this.ribbon)) - { - Trace.WriteLine(string.Format("State not loaded from isolated storage. Because we are in design mode.")); - this.IsStateLoaded = true; - return; - } - - if (this.ribbon.AutomaticStateManagement == false) - { - this.IsStateLoaded = true; - Trace.WriteLine(string.Format("State not loaded from isolated storage. Because automatic state management is disabled.")); - return; - } - - try - { - var storage = GetIsolatedStorageFile(); - if (FileExists(storage, this.IsolatedStorageFileName)) - { - using (var stream = new IsolatedStorageFileStream(this.IsolatedStorageFileName, FileMode.Open, FileAccess.Read, storage)) - { - this.LoadState(stream); - - // Copy loaded state to MemoryStream for temporary storage. - // Temporary storage is used for style changes etc. so we can apply the current state again. - stream.Position = 0; - this.memoryStream.Position = 0; - stream.CopyTo(this.memoryStream); - } - } - } - catch (Exception ex) - { - Trace.WriteLine(string.Format("Error while trying to load Ribbon state. Error: {0}", ex)); - } - - this.IsStateLoaded = true; - } - - /// - /// Loads state from the given stream - /// - /// Stream - private void LoadState(Stream stream) - { - this.ribbon.suppressAutomaticStateManagement = true; - - var reader = new StreamReader(stream); - var splitted = reader.ReadToEnd().Split('|'); - - if (splitted.Length != 2) - { - return; - } - - // Load Ribbon State - var ribbonProperties = splitted[0].Split(','); - - var isMinimized = bool.Parse(ribbonProperties[0]); - - this.ribbon.IsMinimized = isMinimized; - - this.ribbon.ShowQuickAccessToolBarAboveRibbon = bool.Parse(ribbonProperties[1]); - - // Load items - var items = splitted[1].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - - if (this.ribbon.quickAccessToolBar != null) - { - this.ribbon.quickAccessToolBar.Items.Clear(); - } - - this.ribbon.quickAccessElements.Clear(); - - for (var i = 0; i < items.Length; i++) - { - this.ribbon.ParseAndAddToQuickAccessToolBar(items[i]); - } - - // Since application is not fully loaded we have to delay the refresh - this.ribbon.RunInDispatcherAsync(this.ribbon.QuickAccessToolBar.Refresh, DispatcherPriority.Background); - - // Sync QAT menu items - foreach (var menuItem in this.ribbon.QuickAccessItems) - { - menuItem.IsChecked = this.ribbon.IsInQuickAccessToolBar(menuItem.Target); - } - - this.ribbon.suppressAutomaticStateManagement = false; - } - - // Determinates whether the given file exists in the given storage - private static bool FileExists(IsolatedStorageFile storage, string fileName) - { - var files = storage.GetFileNames(fileName); - return files.Length != 0; - } - - // Gets a proper isolated storage file - private static IsolatedStorageFile GetIsolatedStorageFile() - { - try - { - return IsolatedStorageFile.GetUserStoreForDomain(); - } - catch - { - return IsolatedStorageFile.GetUserStoreForAssembly(); - } - } - - /// - /// Resets automatically saved state - /// - public static void ResetState() - { - var storage = GetIsolatedStorageFile(); - - foreach (var filename in storage.GetFileNames("*Fluent.Ribbon.State*")) - { - storage.DeleteFile(filename); - } - } - - private void Dispose(bool disposing) - { - if (disposing == false) - { - return; - } - - if (this.memoryStream != null) - { - this.memoryStream.Dispose(); - } - - this.memoryStream = Stream.Null; - } - - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } - } - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.IO.IsolatedStorage; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Markup; + +namespace Fluent +{ + using System.ComponentModel; + using System.Windows.Threading; + using ControlzEx.Microsoft.Windows.Shell; + using Fluent.Extensions; + + // TODO: improve style parts naming & using + + /// + /// Represents the main Ribbon control which consists of multiple tabs, each of which + /// containing groups of controls. The Ribbon also provides improved context + /// menus, enhanced screen tips, and keyboard shortcuts. + /// + [ContentProperty("Tabs")] + [SuppressMessage("Microsoft.Maintainability", "CA1506")] + [SuppressMessage("Microsoft.Design", "CA1001")] + public class Ribbon : Control + { + private readonly RibbonState ribbonState; + + #region Localization + + // Localizable properties + static readonly RibbonLocalization localization = new RibbonLocalization(); + + /// + /// Gets localizable properties + /// + public static RibbonLocalization Localization + { + get { return localization; } + } + + #endregion + + #region Constants + + /// + /// Minimal width of ribbon parent window + /// + public const double MinimalVisibleWidth = 300; + /// + /// Minimal height of ribbon parent window + /// + public const double MinimalVisibleHeight = 250; + + #endregion + + #region ContextMenu + + private static readonly Dictionary contextMenus = new Dictionary(); + + /// + /// Context menu for ribbon in current thread + /// + public static System.Windows.Controls.ContextMenu RibbonContextMenu + { + get + { + if (!contextMenus.ContainsKey(Thread.CurrentThread.ManagedThreadId)) InitRibbonContextMenu(); + return contextMenus[Thread.CurrentThread.ManagedThreadId]; + } + } + + // Context menu owner ribbon + private static Ribbon contextMenuOwner; + + // Context menu items + private static Dictionary addToQuickAccessMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem addToQuickAccessMenuItem + { + get { return addToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary addGroupToQuickAccessMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem addGroupToQuickAccessMenuItem + { + get { return addGroupToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary addMenuToQuickAccessMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem addMenuToQuickAccessMenuItem + { + get { return addMenuToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary addGalleryToQuickAccessMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem addGalleryToQuickAccessMenuItem + { + get { return addGalleryToQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary removeFromQuickAccessMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem removeFromQuickAccessMenuItem + { + get { return removeFromQuickAccessMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary showQuickAccessToolbarBelowTheRibbonMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem showQuickAccessToolbarBelowTheRibbonMenuItem + { + get { return showQuickAccessToolbarBelowTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary showQuickAccessToolbarAboveTheRibbonMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem showQuickAccessToolbarAboveTheRibbonMenuItem + { + get { return showQuickAccessToolbarAboveTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary minimizeTheRibbonMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem minimizeTheRibbonMenuItem + { + get { return minimizeTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary customizeQuickAccessToolbarMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem customizeQuickAccessToolbarMenuItem + { + get { return customizeQuickAccessToolbarMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary customizeTheRibbonMenuItemDictionary = new Dictionary(); + private static System.Windows.Controls.MenuItem customizeTheRibbonMenuItem + { + get { return customizeTheRibbonMenuItemDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary firstSeparatorDictionary = new Dictionary(); + private static Separator firstSeparator + { + get { return firstSeparatorDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + private static Dictionary secondSeparatorDictionary = new Dictionary(); + private static Separator secondSeparator + { + get { return secondSeparatorDictionary[Thread.CurrentThread.ManagedThreadId]; } + } + + // Initialize ribbon context menu + private static void InitRibbonContextMenu() + { + contextMenus.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.ContextMenu()); + RibbonContextMenu.Opened += OnContextMenuOpened; + + // Add to quick access toolbar + addToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); + RibbonContextMenu.Items.Add(addToQuickAccessMenuItem); + RibbonControl.Bind(Localization, addToQuickAccessMenuItem, "RibbonContextMenuAddItem", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, addToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Add group to quick access toolbar + addGroupToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); + RibbonContextMenu.Items.Add(addGroupToQuickAccessMenuItem); + RibbonControl.Bind(Localization, addGroupToQuickAccessMenuItem, "RibbonContextMenuAddGroup", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, addGroupToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Add menu item to quick access toolbar + addMenuToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); + RibbonContextMenu.Items.Add(addMenuToQuickAccessMenuItem); + RibbonControl.Bind(Localization, addMenuToQuickAccessMenuItem, "RibbonContextMenuAddMenu", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, addMenuToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Add gallery to quick access toolbar + addGalleryToQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = AddToQuickAccessCommand }); + RibbonContextMenu.Items.Add(addGalleryToQuickAccessMenuItem); + RibbonControl.Bind(Localization, addGalleryToQuickAccessMenuItem, "RibbonContextMenuAddGallery", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, addGalleryToQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Remove from quick access toolbar + removeFromQuickAccessMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = RemoveFromQuickAccessCommand }); + RibbonContextMenu.Items.Add(removeFromQuickAccessMenuItem); + RibbonControl.Bind(Localization, removeFromQuickAccessMenuItem, "RibbonContextMenuRemoveItem", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, removeFromQuickAccessMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Separator + firstSeparatorDictionary.Add(Thread.CurrentThread.ManagedThreadId, new Separator()); + RibbonContextMenu.Items.Add(firstSeparator); + + // Customize quick access toolbar + customizeQuickAccessToolbarMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = CustomizeQuickAccessToolbarCommand }); + RibbonContextMenu.Items.Add(customizeQuickAccessToolbarMenuItem); + RibbonControl.Bind(Localization, customizeQuickAccessToolbarMenuItem, "RibbonContextMenuCustomizeQuickAccessToolBar", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, customizeQuickAccessToolbarMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Show quick access below the ribbon + showQuickAccessToolbarBelowTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ShowQuickAccessBelowCommand }); + RibbonContextMenu.Items.Add(showQuickAccessToolbarBelowTheRibbonMenuItem); + RibbonControl.Bind(Localization, showQuickAccessToolbarBelowTheRibbonMenuItem, "RibbonContextMenuShowBelow", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, showQuickAccessToolbarBelowTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Show quick access above the ribbon + showQuickAccessToolbarAboveTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ShowQuickAccessAboveCommand }); + RibbonContextMenu.Items.Add(showQuickAccessToolbarAboveTheRibbonMenuItem); + RibbonControl.Bind(Localization, showQuickAccessToolbarAboveTheRibbonMenuItem, "RibbonContextMenuShowAbove", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, showQuickAccessToolbarAboveTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Separator + secondSeparatorDictionary.Add(Thread.CurrentThread.ManagedThreadId, new Separator()); + RibbonContextMenu.Items.Add(secondSeparator); + + // Customize the ribbon + customizeTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = CustomizeTheRibbonCommand }); + RibbonContextMenu.Items.Add(customizeTheRibbonMenuItem); + RibbonControl.Bind(Localization, customizeTheRibbonMenuItem, "RibbonContextMenuCustomizeRibbon", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, customizeTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + + // Minimize the ribbon + minimizeTheRibbonMenuItemDictionary.Add(Thread.CurrentThread.ManagedThreadId, new System.Windows.Controls.MenuItem { Command = ToggleMinimizeTheRibbonCommand }); + RibbonContextMenu.Items.Add(minimizeTheRibbonMenuItem); + RibbonControl.Bind(Localization, minimizeTheRibbonMenuItem, "RibbonContextMenuMinimizeRibbon", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + RibbonControl.Bind(RibbonContextMenu, minimizeTheRibbonMenuItem, "PlacementTarget", System.Windows.Controls.MenuItem.CommandParameterProperty, BindingMode.OneWay); + } + + /// + /// Invoked whenever an unhandled routed event reaches this class in its route. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnContextMenuOpening(ContextMenuEventArgs e) + { + contextMenuOwner = this; + base.OnContextMenuOpening(e); + } + + /// + /// Invoked whenever an unhandled routed event reaches this class in its route. Implement this method to add class handling for this event. + /// + /// Provides data about the event. + protected override void OnContextMenuClosing(ContextMenuEventArgs e) + { + contextMenuOwner = null; + base.OnContextMenuClosing(e); + } + + // Occurs when context menu is opening + private static void OnContextMenuOpened(object sender, RoutedEventArgs e) + { + var ribbon = contextMenuOwner; + + if (RibbonContextMenu == null + || ribbon == null) + { + return; + } + + addToQuickAccessMenuItem.CommandTarget = ribbon; + addGroupToQuickAccessMenuItem.CommandTarget = ribbon; + addMenuToQuickAccessMenuItem.CommandTarget = ribbon; + addGalleryToQuickAccessMenuItem.CommandTarget = ribbon; + removeFromQuickAccessMenuItem.CommandTarget = ribbon; + customizeQuickAccessToolbarMenuItem.CommandTarget = ribbon; + customizeTheRibbonMenuItem.CommandTarget = ribbon; + minimizeTheRibbonMenuItem.CommandTarget = ribbon; + showQuickAccessToolbarBelowTheRibbonMenuItem.CommandTarget = ribbon; + showQuickAccessToolbarAboveTheRibbonMenuItem.CommandTarget = ribbon; + + // Hide items for ribbon controls + addToQuickAccessMenuItem.Visibility = Visibility.Collapsed; + addGroupToQuickAccessMenuItem.Visibility = Visibility.Collapsed; + addMenuToQuickAccessMenuItem.Visibility = Visibility.Collapsed; + addGalleryToQuickAccessMenuItem.Visibility = Visibility.Collapsed; + removeFromQuickAccessMenuItem.Visibility = Visibility.Collapsed; + firstSeparator.Visibility = Visibility.Collapsed; + + // Hide customize quick access menu item + customizeQuickAccessToolbarMenuItem.Visibility = Visibility.Collapsed; + secondSeparator.Visibility = Visibility.Collapsed; + + // Set minimize the ribbon menu item state + minimizeTheRibbonMenuItem.IsChecked = ribbon.IsMinimized; + + // Set minimize the ribbon menu item visibility + if (ribbon.CanMinimize) + { + minimizeTheRibbonMenuItem.Visibility = Visibility.Visible; + } + else + { + minimizeTheRibbonMenuItem.Visibility = Visibility.Collapsed; + } + + // Set customize the ribbon menu item visibility + if (ribbon.CanCustomizeRibbon) + { + customizeTheRibbonMenuItem.Visibility = Visibility.Visible; + } + else + { + customizeTheRibbonMenuItem.Visibility = Visibility.Collapsed; + } + + // Hide quick access position menu items + showQuickAccessToolbarBelowTheRibbonMenuItem.Visibility = Visibility.Collapsed; + showQuickAccessToolbarAboveTheRibbonMenuItem.Visibility = Visibility.Collapsed; + + // If quick access toolbar is visible show + if (ribbon.IsQuickAccessToolBarVisible) + { + // Set quick access position menu items visibility + if (ribbon.CanQuickAccessLocationChanging) + { + if (ribbon.ShowQuickAccessToolBarAboveRibbon) + { + showQuickAccessToolbarBelowTheRibbonMenuItem.Visibility = Visibility.Visible; + } + else + { + showQuickAccessToolbarAboveTheRibbonMenuItem.Visibility = Visibility.Visible; + } + } + + if (ribbon.CanCustomizeQuickAccessToolBar) + { + customizeQuickAccessToolbarMenuItem.Visibility = Visibility.Visible; + } + + if (ribbon.CanQuickAccessLocationChanging + || ribbon.CanCustomizeQuickAccessToolBar) + { + secondSeparator.Visibility = Visibility.Visible; + } + else + { + secondSeparator.Visibility = Visibility.Collapsed; + } + + if (ribbon.CanCustomizeQuickAccessToolBarItems) + { + // Gets control that raise menu opened + var control = RibbonContextMenu.PlacementTarget; + AddToQuickAccessCommand.CanExecute(null, control); + RemoveFromQuickAccessCommand.CanExecute(null, control); + + //Debug.WriteLine("Menu opened on "+control); + if (control != null) + { + firstSeparator.Visibility = Visibility.Visible; + + // Check for value because remove is only possible in the context menu of items in QA which represent the value for QA-items + if (ribbon.quickAccessElements.ContainsValue(control)) + { + // Control is on quick access + removeFromQuickAccessMenuItem.Visibility = Visibility.Visible; + } + else if (control is System.Windows.Controls.MenuItem) + { + // Control is menu item + addMenuToQuickAccessMenuItem.Visibility = Visibility.Visible; + } + else if ((control is Gallery) || + (control is InRibbonGallery)) + { + // Control is gallery + addGalleryToQuickAccessMenuItem.Visibility = Visibility.Visible; + } + else if (control is RibbonGroupBox) + { + // Control is group box + addGroupToQuickAccessMenuItem.Visibility = Visibility.Visible; + } + else if (control is IQuickAccessItemProvider) + { + // Its other control + addToQuickAccessMenuItem.Visibility = Visibility.Visible; + } + else + { + firstSeparator.Visibility = Visibility.Collapsed; + } + } + } + } + } + + #endregion + + #region Events + + /// + /// Occurs when selected tab has been changed (be aware that SelectedTab can be null) + /// + public event SelectionChangedEventHandler SelectedTabChanged; + + /// + /// Occurs when customize the ribbon + /// + public event EventHandler CustomizeTheRibbon; + + /// + /// Occurs when customize quick access toolbar + /// + public event EventHandler CustomizeQuickAccessToolbar; + + /// + /// Occurs when IsMinimized property is changing + /// + public event DependencyPropertyChangedEventHandler IsMinimizedChanged; + + /// + /// Occurs when IsCollapsed property is changing + /// + public event DependencyPropertyChangedEventHandler IsCollapsedChanged; + + #endregion + + #region Fields + + // Collection of contextual tab groups + private ObservableCollection contextualGroups; + + // Collection of tabs + private ObservableCollection tabs; + + // Collection of toolbar items + private ObservableCollection toolBarItems; + + // Ribbon quick access toolbar + private QuickAccessToolBar quickAccessToolBar; + + // Ribbon layout root + private Panel layoutRoot; + + // Handles F10, Alt and so on + readonly KeyTipService keyTipService; + + // Collection of quickaccess menu items + private ObservableCollection quickAccessItems; + + // Currently added in QAT items + private readonly Dictionary quickAccessElements = new Dictionary(); + + private Window ownerWindow; + + #endregion + + #region Properties + + #region Menu + + /// + /// Gets or sets file menu control (can be application menu button, backstage button and so on) + /// + public UIElement Menu + { + get { return (UIElement)this.GetValue(MenuProperty); } + set { this.SetValue(MenuProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Button. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MenuProperty = + DependencyProperty.Register(nameof(Menu), typeof(UIElement), typeof(Ribbon), new UIPropertyMetadata(null, AddOrRemoveLogicalChildOnPropertyChanged)); + + #endregion + + /// + /// Property for defining the start screen. + /// + public StartScreen StartScreen + { + get { return (StartScreen)this.GetValue(StartScreenProperty); } + set { this.SetValue(StartScreenProperty, value); } + } + + /// + /// for + /// + public static readonly DependencyProperty StartScreenProperty = + DependencyProperty.Register(nameof(StartScreen), typeof(StartScreen), typeof(Ribbon), new UIPropertyMetadata(null, AddOrRemoveLogicalChildOnPropertyChanged)); + + /// + /// Window title + /// + public string Title + { + get { return (string)this.GetValue(TitleProperty); } + set { this.SetValue(TitleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register(nameof(Title), typeof(string), typeof(Ribbon), new UIPropertyMetadata(string.Empty, OnTitleChanged)); + + private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + + ribbon?.TitleBar?.InvalidateMeasure(); + } + + /// + /// Gets or sets selected tab item + /// + public RibbonTabItem SelectedTabItem + { + get { return (RibbonTabItem)this.GetValue(SelectedTabItemProperty); } + set { this.SetValue(SelectedTabItemProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectedTabItem. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedTabItemProperty = + DependencyProperty.Register("SelectedTabItem", typeof(RibbonTabItem), typeof(Ribbon), new UIPropertyMetadata(null, OnSelectedTabItemChanged)); + + private static void OnSelectedTabItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (ribbon.TabControl != null) + { + ribbon.TabControl.SelectedItem = e.NewValue; + } + + var selectedItem = e.NewValue as RibbonTabItem; + + if (selectedItem != null + && ribbon.Tabs.Contains(selectedItem)) + { + ribbon.SelectedTabIndex = ribbon.Tabs.IndexOf(selectedItem); + } + else + { + ribbon.SelectedTabIndex = -1; + } + } + + /// + /// Gets or sets selected tab index + /// + public int SelectedTabIndex + { + get { return (int)this.GetValue(SelectedTabIndexProperty); } + set { this.SetValue(SelectedTabIndexProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectedTabindex. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedTabIndexProperty = + DependencyProperty.Register("SelectedTabIndex", typeof(int), typeof(Ribbon), new UIPropertyMetadata(-1, OnSelectedTabIndexChanged)); + + private static void OnSelectedTabIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + var selectedIndex = (int)e.NewValue; + + if (ribbon.TabControl != null) + { + ribbon.TabControl.SelectedIndex = selectedIndex; + } + + if (selectedIndex >= 0 + && selectedIndex < ribbon.Tabs.Count) + { + ribbon.SelectedTabItem = ribbon.Tabs[selectedIndex]; + } + else + { + ribbon.SelectedTabItem = null; + } + } + + private static void AddOrRemoveLogicalChildOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (e.OldValue != null) + { + ribbon.RemoveLogicalChild(e.OldValue); + } + + if (e.NewValue != null) + { + ribbon.AddLogicalChild(e.NewValue); + } + } + + /// + /// Gets the first visible TabItem + /// + public RibbonTabItem FirstVisibleItem + { + get + { + return this.GetFirstVisibleItem(); + } + } + + /// + /// Gets the last visible TabItem + /// + public RibbonTabItem LastVisibleItem + { + get + { + return this.GetLastVisibleItem(); + } + } + + /// + /// Gets the list of currently active quick access elements. + /// + protected Dictionary QuickAccessElements + { + get + { + return this.quickAccessElements; + } + } + + /// + /// Gets ribbon titlebar + /// + internal RibbonTitleBar TitleBar { get; private set; } + + /// + /// Gets the Ribbon tab control + /// + internal RibbonTabControl TabControl { get; private set; } + + /// + /// Gets or sets whether quick access toolbar showes above ribbon + /// + public bool ShowQuickAccessToolBarAboveRibbon + { + get { return (bool)this.GetValue(ShowQuickAccessToolBarAboveRibbonProperty); } + set { this.SetValue(ShowQuickAccessToolBarAboveRibbonProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ShowAboveRibbon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ShowQuickAccessToolBarAboveRibbonProperty = + DependencyProperty.Register("ShowQuickAccessToolBarAboveRibbon", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true, OnShowQuickAccesToolBarAboveRibbonChanged)); + + /// + /// Handles ShowQuickAccessToolBarAboveRibbon property changed + /// + /// Object + /// The event data + private static void OnShowQuickAccesToolBarAboveRibbonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (ribbon.TitleBar != null) + { + ribbon.TitleBar.InvalidateMeasure(); + } + + ribbon.ribbonState.SaveStateToMemoryStream(); + } + + /// + /// Gets collection of contextual tab groups + /// + public ObservableCollection ContextualGroups + { + get + { + if (this.contextualGroups == null) + { + this.contextualGroups = new ObservableCollection(); + this.contextualGroups.CollectionChanged += this.OnContextualGroupsCollectionChanged; + } + + return this.contextualGroups; + } + } + + /// + /// Handles collection of contextual tab groups ghanges + /// + /// Sender + /// The event data + private void OnContextualGroupsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (int i = 0; i < e.NewItems.Count; i++) + { + if (this.TitleBar != null) this.TitleBar.Items.Insert(e.NewStartingIndex + i, e.NewItems[i]); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (object item in e.OldItems) + { + if (this.TitleBar != null) this.TitleBar.Items.Remove(item); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (object item in e.OldItems) + { + if (this.TitleBar != null) this.TitleBar.Items.Remove(item); + } + foreach (object item in e.NewItems) + { + if (this.TitleBar != null) this.TitleBar.Items.Add(item); + } + break; + case NotifyCollectionChangedAction.Reset: + if (this.TitleBar != null) this.TitleBar.Items.Clear(); + break; + } + + } + + /// + /// gets collection of ribbon tabs + /// + public ObservableCollection Tabs + { + get + { + if (this.tabs == null) + { + this.tabs = new ObservableCollection(); + this.tabs.CollectionChanged += this.OnTabsCollectionChanged; + } + + return this.tabs; + } + } + + /// + /// Handles collection of ribbon tabs changed + /// + /// Sender + /// The event data + private void OnTabsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (this.TabControl == null) + { + return; + } + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (var i = 0; i < e.NewItems.Count; i++) + { + this.TabControl.Items.Insert(e.NewStartingIndex + i, e.NewItems[i]); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems) + { + this.TabControl.Items.Remove(item); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var item in e.OldItems) + { + this.TabControl.Items.Remove(item); + } + + foreach (var item in e.NewItems) + { + this.TabControl.Items.Add(item); + } + break; + + case NotifyCollectionChangedAction.Reset: + this.TabControl.Items.Clear(); + break; + } + } + + /// + /// Gets collection of toolbar items + /// + public ObservableCollection ToolBarItems + { + get + { + if (this.toolBarItems == null) + { + this.toolBarItems = new ObservableCollection(); + this.toolBarItems.CollectionChanged += this.OnToolbarItemsCollectionChanged; + } + + return this.toolBarItems; + } + } + + /// + /// Handles collection of toolbar items changes + /// + /// Sender + /// The event data + private void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (int i = 0; i < e.NewItems.Count; i++) + { + if (this.TabControl != null) + this.TabControl.ToolBarItems.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (object item in e.OldItems) + { + if (this.TabControl != null) + this.TabControl.ToolBarItems.Remove(item as UIElement); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (object item in e.OldItems) + { + if (this.TabControl != null) + this.TabControl.ToolBarItems.Remove(item as UIElement); + } + foreach (object item in e.NewItems) + { + if (this.TabControl != null) + this.TabControl.ToolBarItems.Add(item as UIElement); + } + break; + } + + } + + /// + /// Gets quick access toolbar associated with the ribbon + /// + internal QuickAccessToolBar QuickAccessToolBar + { + get { return this.quickAccessToolBar; } + } + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + if (this.layoutRoot != null) + { + yield return this.layoutRoot; + } + + if (this.Menu != null) + { + yield return this.Menu; + } + + if (this.StartScreen != null) + { + yield return this.StartScreen; + } + + if (this.quickAccessToolBar != null) + { + yield return this.quickAccessToolBar; + } + + if (this.TabControl != null + && this.TabControl.ToolbarPanel != null) + { + yield return this.TabControl.ToolbarPanel; + } + } + } + + /// + /// Gets collection of quick access menu items + /// + public ObservableCollection QuickAccessItems + { + get + { + if (this.quickAccessItems == null) + { + this.quickAccessItems = new ObservableCollection(); + this.quickAccessItems.CollectionChanged += this.OnQuickAccessItemsCollectionChanged; + } + + return this.quickAccessItems; + } + } + + /// + /// Handles collection of quick access menu items changes + /// + /// Sender + /// The event data + private void OnQuickAccessItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (var i = 0; i < e.NewItems.Count; i++) + { + var menuItem = (QuickAccessMenuItem)e.NewItems[i]; + if (this.quickAccessToolBar != null) + { + this.quickAccessToolBar.QuickAccessItems.Insert(e.NewStartingIndex + i, menuItem); + } + menuItem.Ribbon = this; + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems.OfType()) + { + var menuItem = item; + if (this.quickAccessToolBar != null) + { + this.quickAccessToolBar.QuickAccessItems.Remove(menuItem); + } + menuItem.Ribbon = null; + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var item in e.OldItems.OfType()) + { + var menuItem = item; + if (this.quickAccessToolBar != null) + { + this.quickAccessToolBar.QuickAccessItems.Remove(menuItem); + } + menuItem.Ribbon = null; + } + foreach (var item in e.NewItems.OfType()) + { + var menuItem = item; + if (this.quickAccessToolBar != null) + { + this.quickAccessToolBar.QuickAccessItems.Add(menuItem); + } + menuItem.Ribbon = this; + } + break; + } + } + + /// + /// Gets or sets whether Customize Quick Access Toolbar menu item is shown + /// + public bool CanCustomizeQuickAccessToolBar + { + get { return (bool)this.GetValue(CanCustomizeQuickAccessToolBarProperty); } + set { this.SetValue(CanCustomizeQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanCustomizeQuickAccessToolBar. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanCustomizeQuickAccessToolBarProperty = + DependencyProperty.Register("CanCustomizeQuickAccessToolBar", typeof(bool), + typeof(Ribbon), new UIPropertyMetadata(false)); + + /// + /// Gets or sets whether items can be added or removed from the quick access toolbar by users. + /// + public bool CanCustomizeQuickAccessToolBarItems + { + get { return (bool)this.GetValue(CanCustomizeQuickAccessToolBarItemsProperty); } + set { this.SetValue(CanCustomizeQuickAccessToolBarItemsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanCustomizeQuickAccessToolBarItems. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanCustomizeQuickAccessToolBarItemsProperty = + DependencyProperty.Register("CanCustomizeQuickAccessToolBarItems", typeof(bool), typeof(Ribbon), new PropertyMetadata(true)); + + /// + /// Gets or sets whether Customize Ribbon menu item is shown + /// + public bool CanCustomizeRibbon + { + get { return (bool)this.GetValue(CanCustomizeRibbonProperty); } + set { this.SetValue(CanCustomizeRibbonProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanCustomizeRibbon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanCustomizeRibbonProperty = + DependencyProperty.Register("CanCustomizeRibbon", typeof(bool), + typeof(Ribbon), new UIPropertyMetadata(false)); + + /// + /// Gets or sets whether ribbon can be minimized + /// + public bool CanMinimize + { + get { return (bool)this.GetValue(CanMinimizeProperty); } + set { this.SetValue(CanMinimizeProperty, value); } + } + + /// + /// Gets or sets whether ribbon is minimized + /// + public bool IsMinimized + { + get { return (bool)this.GetValue(IsMinimizedProperty); } + set { this.SetValue(IsMinimizedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsMinimized. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsMinimizedProperty = + DependencyProperty.Register("IsMinimized", typeof(bool), + typeof(Ribbon), new UIPropertyMetadata(false, OnIsMinimizedChanged)); + + /// + /// Using a DependencyProperty as the backing store for CanMinimize. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanMinimizeProperty = + DependencyProperty.Register("CanMinimize", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true, OnCanMinimizeChanged)); + + + private static void OnIsMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + + if (ribbon.IsMinimizedChanged != null) + { + ribbon.IsMinimizedChanged(ribbon, e); + } + } + + private static void OnCanMinimizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (ribbon.TabControl != null) + { + ribbon.TabControl.CanMinimize = ribbon.CanMinimize; + } + } + + /// + /// Gets or sets the height of the gap between the ribbon and the content + /// + public double ContentGapHeight + { + get { return (double)this.GetValue(ContentGapHeightProperty); } + set { this.SetValue(ContentGapHeightProperty, value); } + } + + /// + /// DependencyProperty for + /// + public static readonly DependencyProperty ContentGapHeightProperty = + DependencyProperty.Register("ContentGapHeight", typeof(double), typeof(Ribbon), new UIPropertyMetadata(5D)); + + // todo check if IsCollapsed and IsAutomaticCollapseEnabled should be reduced to one shared property for RibbonWindow and Ribbon + /// + /// Gets whether ribbon is collapsed + /// + public bool IsCollapsed + { + get { return (bool)this.GetValue(IsCollapsedProperty); } + set { this.SetValue(IsCollapsedProperty, value); } + } + + /// + /// DependencyProperty for + /// + public static readonly DependencyProperty IsCollapsedProperty = + DependencyProperty.Register("IsCollapsed", typeof(bool), + typeof(Ribbon), new FrameworkPropertyMetadata(false, OnIsCollapsedChanged)); + + private static void OnIsCollapsedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (ribbon.IsCollapsedChanged != null) + { + ribbon.IsCollapsedChanged(ribbon, e); + } + } + + /// + /// Defines if the Ribbon should automatically set when the width or height of the owner window drop under or + /// + public bool IsAutomaticCollapseEnabled + { + get { return (bool)this.GetValue(IsAutomaticCollapseEnabledProperty); } + set { this.SetValue(IsAutomaticCollapseEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsCollapsed. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsAutomaticCollapseEnabledProperty = + DependencyProperty.Register("IsAutomaticCollapseEnabled", typeof(bool), typeof(Ribbon), new PropertyMetadata(true)); + + /// + /// Gets or sets whether QAT is visible + /// + public bool IsQuickAccessToolBarVisible + { + get { return (bool)this.GetValue(IsQuickAccessToolBarVisibleProperty); } + set { this.SetValue(IsQuickAccessToolBarVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsQuickAccessToolBarVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsQuickAccessToolBarVisibleProperty = + DependencyProperty.Register("IsQuickAccessToolBarVisible", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true)); + + + /// + /// Gets or sets whether user can change location of QAT + /// + public bool CanQuickAccessLocationChanging + { + get { return (bool)this.GetValue(CanQuickAccessLocationChangingProperty); } + set { this.SetValue(CanQuickAccessLocationChangingProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanQuickAccessLocationChanging. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanQuickAccessLocationChangingProperty = + DependencyProperty.Register("CanQuickAccessLocationChanging", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true)); + + + /// + /// Checks if any keytips are visible. + /// + public bool AreAnyKeyTipsVisible + { + get + { + if (this.keyTipService != null) + { + return this.keyTipService.AreAnyKeyTipsVisible; + } + + return false; + } + } + #endregion + + #region Commands + + /// + /// Gets add to quick access toolbar command + /// + public static RoutedCommand AddToQuickAccessCommand = new RoutedCommand("AddToQuickAccessCommand", typeof(Ribbon)); + + /// + /// Gets remove from quick access command + /// + public static RoutedCommand RemoveFromQuickAccessCommand = new RoutedCommand("RemoveFromQuickAccessCommand", typeof(Ribbon)); + + /// + /// Gets show quick access above command + /// + public static RoutedCommand ShowQuickAccessAboveCommand = new RoutedCommand("ShowQuickAccessAboveCommand", typeof(Ribbon)); + + /// + /// Gets show quick access below command + /// + public static RoutedCommand ShowQuickAccessBelowCommand = new RoutedCommand("ShowQuickAccessBelowCommand", typeof(Ribbon)); + + /// + /// Gets toggle ribbon minimize command + /// + public static RoutedCommand ToggleMinimizeTheRibbonCommand = new RoutedCommand("ToggleMinimizeTheRibbonCommand", typeof(Ribbon)); + + /// + /// Gets customize quick access toolbar command + /// + public static RoutedCommand CustomizeQuickAccessToolbarCommand = new RoutedCommand("CustomizeQuickAccessToolbarCommand", typeof(Ribbon)); + + /// + /// Gets customize the ribbon command + /// + public static RoutedCommand CustomizeTheRibbonCommand = new RoutedCommand("CustomizeTheRibbonCommand", typeof(Ribbon)); + + // Occurs when customize toggle minimize command can execute handles + private static void OnToggleMinimizeTheRibbonCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon != null + && ribbon.TabControl != null) + { + e.CanExecute = ribbon.CanMinimize; + } + } + + // Occurs when toggle minimize command executed + private static void OnToggleMinimizeTheRibbonCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + if (ribbon != null + && ribbon.TabControl != null) + { + ribbon.TabControl.IsMinimized = !ribbon.TabControl.IsMinimized; + } + } + + // Occurs when show quick access below command executed + private static void OnShowQuickAccessBelowCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + ribbon.ShowQuickAccessToolBarAboveRibbon = false; + } + + // Occurs when show quick access above command executed + private static void OnShowQuickAccessAboveCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + ribbon.ShowQuickAccessToolBarAboveRibbon = true; + } + + // Occurs when remove from quick access command executed + private static void OnRemoveFromQuickAccessCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + if (ribbon.quickAccessToolBar != null) + { + var element = ribbon.quickAccessElements.First(x => x.Value == e.Parameter).Key; + ribbon.RemoveFromQuickAccessToolBar(element); + } + } + + // Occurs when add to quick access command executed + private static void OnAddToQuickAccessCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + if (ribbon.quickAccessToolBar != null) + { + ribbon.AddToQuickAccessToolBar(e.Parameter as UIElement); + } + } + + // Occurs when customize quick access command executed + private static void OnCustomizeQuickAccessToolbarCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + if (ribbon.CustomizeQuickAccessToolbar != null) + { + ribbon.CustomizeQuickAccessToolbar(sender, EventArgs.Empty); + } + } + + // Occurs when customize the ribbon command executed + private static void OnCustomizeTheRibbonCommandExecuted(object sender, ExecutedRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + if (ribbon.CustomizeTheRibbon != null) + { + ribbon.CustomizeTheRibbon(sender, EventArgs.Empty); + } + } + + // Occurs when customize quick access command can execute handles + private static void OnCustomizeQuickAccessToolbarCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + e.CanExecute = ribbon.CanCustomizeQuickAccessToolBar; + } + + // Occurs when customize the ribbon command can execute handles + private static void OnCustomizeTheRibbonCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + e.CanExecute = ribbon.CanCustomizeRibbon; + } + + // Occurs when remove from quick access command can execute handles + private static void OnRemoveFromQuickAccessCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon == null) + { + return; + } + + if (ribbon.IsQuickAccessToolBarVisible) + { + e.CanExecute = ribbon.quickAccessElements.ContainsValue(e.Parameter as UIElement); + } + else + { + e.CanExecute = false; + } + } + + // Occurs when add to quick access command can execute handles + private static void OnAddToQuickAccessCommandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + var ribbon = sender as Ribbon; + + if (ribbon != null + && ribbon.IsQuickAccessToolBarVisible + && QuickAccessItemsProvider.IsSupported(e.Parameter as UIElement) + && ribbon.IsInQuickAccessToolBar(e.Parameter as UIElement) == false) + { + if (e.Parameter is Gallery) + { + e.CanExecute = ribbon.IsInQuickAccessToolBar(FindParentRibbonControl(e.Parameter as DependencyObject) as UIElement) == false; + } + else + { + e.CanExecute = ribbon.IsInQuickAccessToolBar(e.Parameter as UIElement) == false; + } + } + else + { + e.CanExecute = false; + } + } + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static Ribbon() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Ribbon), new FrameworkPropertyMetadata(typeof(Ribbon))); + + // Subscribe to menu commands + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(AddToQuickAccessCommand, OnAddToQuickAccessCommandExecuted, OnAddToQuickAccessCommandCanExecute)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(RemoveFromQuickAccessCommand, OnRemoveFromQuickAccessCommandExecuted, OnRemoveFromQuickAccessCommandCanExecute)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ShowQuickAccessAboveCommand, OnShowQuickAccessAboveCommandExecuted)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ShowQuickAccessBelowCommand, OnShowQuickAccessBelowCommandExecuted)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(ToggleMinimizeTheRibbonCommand, OnToggleMinimizeTheRibbonCommandExecuted, OnToggleMinimizeTheRibbonCommandCanExecute)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(CustomizeTheRibbonCommand, OnCustomizeTheRibbonCommandExecuted, OnCustomizeTheRibbonCommandCanExecute)); + CommandManager.RegisterClassCommandBinding(typeof(Ribbon), new CommandBinding(CustomizeQuickAccessToolbarCommand, OnCustomizeQuickAccessToolbarCommandExecuted, OnCustomizeQuickAccessToolbarCommandCanExecute)); + + InitRibbonContextMenu(); + } + + /// + /// Default constructor + /// + public Ribbon() + { + this.VerticalAlignment = VerticalAlignment.Top; + KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Contained); + + WindowChrome.SetIsHitTestVisibleInChrome(this, true); + + this.keyTipService = new KeyTipService(this); + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + + this.ribbonState = new RibbonState(this); + } + + #endregion + + #region Overrides + + private void OnSizeChanged(object sender, SizeChangedEventArgs e) + { + this.MaintainIsCollapsed(); + } + + private void MaintainIsCollapsed() + { + if (this.IsAutomaticCollapseEnabled == false + || this.ownerWindow == null) + { + return; + } + + if (this.ownerWindow.ActualWidth < MinimalVisibleWidth + || this.ownerWindow.ActualHeight < MinimalVisibleHeight) + { + this.IsCollapsed = true; + } + else + { + this.IsCollapsed = false; + } + } + + /// + /// Invoked whenever an unhandled System.Windows.UIElement.GotFocus + /// event reaches this element in its route. + /// + /// The System.Windows.RoutedEventArgs that contains the event data. + protected override void OnGotFocus(RoutedEventArgs e) + { + if (this.TabControl == null) + { + return; + } + + var ribbonTabItem = (RibbonTabItem)this.TabControl.SelectedItem; + if (ribbonTabItem != null) + { + ribbonTabItem.Focus(); + } + } + + /// + /// When overridden in a derived class, is invoked whenever application code or + /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + public override void OnApplyTemplate() + { + if (this.layoutRoot != null) + { + this.RemoveLogicalChild(this.layoutRoot); + } + + this.layoutRoot = this.GetTemplateChild("PART_LayoutRoot") as Panel; + + if (this.layoutRoot != null) + { + this.AddLogicalChild(this.layoutRoot); + } + + if (this.TitleBar != null) + { + foreach (var ribbonContextualTabGroup in this.ContextualGroups) + { + this.TitleBar.Items.Remove(ribbonContextualTabGroup); + } + + // Make sure everything is cleared + this.TitleBar.Items.Clear(); + } + + this.TitleBar = this.GetTemplateChild("PART_RibbonTitleBar") as RibbonTitleBar; + + if (this.TitleBar != null) + { + foreach (var contextualTabGroup in this.ContextualGroups) + { + this.TitleBar.Items.Add(contextualTabGroup); + } + } + + var selectedTab = this.SelectedTabItem; + if (this.TabControl != null) + { + this.TabControl.SelectionChanged -= this.OnTabControlSelectionChanged; + selectedTab = this.TabControl.SelectedItem as RibbonTabItem; + + foreach (var ribbonTabItem in this.Tabs) + { + this.TabControl.Items.Remove(ribbonTabItem); + } + + // Make sure everything is cleared + this.TabControl.Items.Clear(); + + foreach (var toolBarItem in this.ToolBarItems) + { + this.TabControl.ToolBarItems.Remove(toolBarItem); + } + + // Make sure everything is cleared + this.TabControl.ToolBarItems.Clear(); + } + + this.TabControl = this.GetTemplateChild("PART_RibbonTabControl") as RibbonTabControl; + + if (this.TabControl != null) + { + this.TabControl.SelectionChanged += this.OnTabControlSelectionChanged; + + this.TabControl.CanMinimize = this.CanMinimize; + this.TabControl.IsMinimized = this.IsMinimized; + this.TabControl.ContentGapHeight = this.ContentGapHeight; + + this.TabControl.SetBinding(RibbonTabControl.IsMinimizedProperty, new Binding("IsMinimized") { Source = this, Mode = BindingMode.TwoWay }); + this.TabControl.SetBinding(RibbonTabControl.ContentGapHeightProperty, new Binding("ContentGapHeight") { Source = this, Mode = BindingMode.OneWay }); + + foreach (var ribbonTabItem in this.Tabs) + { + this.TabControl.Items.Add(ribbonTabItem); + } + + this.TabControl.SelectedItem = selectedTab; + + foreach (var toolBarItem in this.ToolBarItems) + { + this.TabControl.ToolBarItems.Add(toolBarItem); + } + } + + if (this.quickAccessToolBar != null) + { + if (this.AutomaticStateManagement == false + || this.ribbonState.IsStateLoaded) + { + this.ribbonState.SaveStateToMemoryStream(); + } + + this.ClearQuickAccessToolBar(); + + this.quickAccessToolBar.ItemsChanged -= this.OnQuickAccessItemsChanged; + + foreach (var quickAccessMenuItem in this.QuickAccessItems) + { + this.quickAccessToolBar.QuickAccessItems.Remove(quickAccessMenuItem); + } + } + + this.quickAccessToolBar = this.GetTemplateChild("PART_QuickAccessToolBar") as QuickAccessToolBar; + + if (this.quickAccessToolBar != null) + { + foreach (var quickAccessMenuItem in this.QuickAccessItems) + { + this.quickAccessToolBar.QuickAccessItems.Add(quickAccessMenuItem); + } + + this.quickAccessToolBar.ItemsChanged += this.OnQuickAccessItemsChanged; + + var binding = new Binding("CanQuickAccessLocationChanging") + { + Source = this, + Mode = BindingMode.OneWay + }; + this.quickAccessToolBar.SetBinding(QuickAccessToolBar.CanQuickAccessLocationChangingProperty, binding); + + if (this.quickAccessToolBar.Parent == null) + { + this.AddLogicalChild(this.quickAccessToolBar); + } + + this.quickAccessToolBar.Loaded += this.OnFirstToolbarLoaded; + } + } + + /// + /// Called when the is closed, so that we set it to null and clear the + /// + private void OnOwnerWindowClosed(object sender, EventArgs e) + { + this.DetachFromWindow(); + } + + private void AttachToWindow() + { + this.DetachFromWindow(); + + this.ownerWindow = Window.GetWindow(this); + + if (this.ownerWindow != null) + { + this.ownerWindow.Closed += this.OnOwnerWindowClosed; + this.ownerWindow.SizeChanged += this.OnSizeChanged; + this.ownerWindow.KeyDown += this.OnKeyDown; + + var binding = new Binding("Title") + { + Mode = BindingMode.OneWay, + Source = this.ownerWindow + }; + this.SetBinding(TitleProperty, binding); + } + } + + private void DetachFromWindow() + { + if (this.ownerWindow != null) + { + this.ribbonState.SaveStateToIsolatedStorage(); + + this.ownerWindow.Closed -= this.OnOwnerWindowClosed; + this.ownerWindow.SizeChanged -= this.OnSizeChanged; + this.ownerWindow.KeyDown -= this.OnKeyDown; + + BindingOperations.ClearBinding(this, TitleProperty); + } + + this.ownerWindow = null; + } + + private void OnFirstToolbarLoaded(object sender, RoutedEventArgs e) + { + this.quickAccessToolBar.Loaded -= this.OnFirstToolbarLoaded; + + this.ribbonState.LoadStateFromMemoryStream(); + } + + #endregion + + #region Quick Access Items Managment + + /// + /// Determines whether the given element is in quick access toolbar + /// + /// Element + /// True if element in quick access toolbar + public bool IsInQuickAccessToolBar(UIElement element) + { + if (element == null) + { + return false; + } + + return this.quickAccessElements.ContainsKey(element); + } + + /// + /// Adds the given element to quick access toolbar + /// + /// Element + public void AddToQuickAccessToolBar(UIElement element) + { + if (element == null) + { + return; + } + + if (element is Gallery) + { + element = FindParentRibbonControl(element) as UIElement; + } + + // Do not add menu items without icon. + var menuItem = element as MenuItem; + if (menuItem != null && menuItem.Icon == null) + { + element = FindParentRibbonControl(element) as UIElement; + } + + if (element == null) + { + return; + } + + if (QuickAccessItemsProvider.IsSupported(element) == false) + { + return; + } + + if (this.IsInQuickAccessToolBar(element) == false) + { + Debug.WriteLine("Adding \"{0}\" to QuickAccessToolBar.", element); + + var control = QuickAccessItemsProvider.GetQuickAccessItem(element); + + this.quickAccessElements.Add(element, control); + this.quickAccessToolBar.Items.Add(control); + } + } + + private static IRibbonControl FindParentRibbonControl(DependencyObject element) + { + var parent = LogicalTreeHelper.GetParent(element); + + while (parent != null) + { + var control = parent as IRibbonControl; + if (control != null) + { + return control; + } + + parent = LogicalTreeHelper.GetParent(parent); + } + + return null; + } + + /// + /// Removes the given elements from quick access toolbar + /// + /// Element + public void RemoveFromQuickAccessToolBar(UIElement element) + { + Debug.WriteLine("Removing \"{0}\" from QuickAccessToolBar.", element); + + if (this.IsInQuickAccessToolBar(element)) + { + var quickAccessItem = this.quickAccessElements[element]; + this.quickAccessElements.Remove(element); + this.quickAccessToolBar.Items.Remove(quickAccessItem); + } + } + + /// + /// Clears quick access toolbar + /// + public void ClearQuickAccessToolBar() + { + this.quickAccessElements.Clear(); + if (this.quickAccessToolBar != null) + { + this.quickAccessToolBar.Items.Clear(); + } + } + + #endregion + + #region Event Handling + + // Handles tab control selection changed + private void OnTabControlSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (this.TabControl != null) + { + this.SelectedTabItem = this.TabControl.SelectedItem as RibbonTabItem; + this.SelectedTabIndex = this.TabControl.SelectedIndex; + } + + if (this.SelectedTabChanged != null) + { + this.SelectedTabChanged(this, e); + } + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.keyTipService.Attach(); + + this.AttachToWindow(); + + this.LoadInitialState(); + } + + private void OnKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.F1 + && Keyboard.Modifiers.HasFlag(ModifierKeys.Control)) + { + if (this.TabControl.HasItems) + { + if (this.CanMinimize) + { + this.IsMinimized = !this.IsMinimized; + } + } + } + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.ribbonState.SaveStateToIsolatedStorage(); + + this.keyTipService.Detach(); + + if (this.ownerWindow != null) + { + this.ownerWindow.SizeChanged -= this.OnSizeChanged; + this.ownerWindow.KeyDown -= this.OnKeyDown; + } + } + + #endregion + + #region Private methods + + private RibbonTabItem GetFirstVisibleItem() + { + return this.Tabs.FirstOrDefault(item => item.Visibility == Visibility.Visible); + } + + private RibbonTabItem GetLastVisibleItem() + { + return this.Tabs.LastOrDefault(item => item.Visibility == Visibility.Visible); + } + + #endregion + + #region State Management + + private void LoadInitialState() + { + if (this.ribbonState.IsStateLoaded) + { + return; + } + + this.ribbonState.LoadStateFromIsolatedStorage(); + + if (this.TabControl != null + && this.TabControl.SelectedIndex == -1 + && this.TabControl.IsMinimized == false) + { + this.TabControl.SelectedItem = this.TabControl.GetFirstVisibleItem(); + } + } + + // Handles items changing in QAT + private void OnQuickAccessItemsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.ribbonState.SaveStateToMemoryStream(); + } + + // Traverse logical tree and find QAT items, remember paths + private void TraverseLogicalTree(DependencyObject item, string path, IDictionary paths) + { + // Is this item in QAT + var uielement = item as FrameworkElement; + if (uielement != null + && this.quickAccessElements.ContainsKey(uielement)) + { + if (!paths.ContainsKey(uielement)) + { + paths.Add(uielement, path); + } + } + + var children = LogicalTreeHelper.GetChildren(item).Cast().ToArray(); + for (var i = 0; i < children.Length; i++) + { + var child = children[i] as DependencyObject; + if (child == null) + { + continue; + } + + this.TraverseLogicalTree(child, path + i + ",", paths); + } + } + + #endregion + + #region Load from Stream + + // Loads item and add to QAT + private void ParseAndAddToQuickAccessToolBar(string data) + { + var indices = data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => int.Parse(x, CultureInfo.InvariantCulture)).ToArray(); + + DependencyObject current = this; + + for (var i = 0; i < indices.Length; i++) + { + var children = LogicalTreeHelper.GetChildren(current).OfType().ToArray(); + var indexIsInvalid = children.Length <= indices[i]; + var item = indexIsInvalid + ? null + : children[indices[i]] as DependencyObject; + + if (item == null) + { + // Path is incorrect + Debug.WriteLine("Error while QAT items loading: one of the paths is invalid"); + return; + } + + current = item; + } + + var result = current as UIElement; + if (result == null + || QuickAccessItemsProvider.IsSupported(result) == false) + { + // Item is invalid + Debug.WriteLine("Error while QAT items loading. Could not add \"{0}\" to QAT.", current); + return; + } + + this.AddToQuickAccessToolBar(result); + } + + #endregion + + #region AutomaticStateManagement Property + + // To temporary suppress automatic management + private bool suppressAutomaticStateManagement; + + /// + /// Gets or sets whether Quick Access ToolBar can + /// save and load its state automatically + /// + public bool AutomaticStateManagement + { + get { return (bool)this.GetValue(AutomaticStateManagementProperty); } + set { this.SetValue(AutomaticStateManagementProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for AutomaticStateManagement. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty AutomaticStateManagementProperty = + DependencyProperty.Register("AutomaticStateManagement", typeof(bool), typeof(Ribbon), new UIPropertyMetadata(true, OnAutoStateManagement, CoerceAutoStateManagement)); + + private static object CoerceAutoStateManagement(DependencyObject d, object basevalue) + { + var ribbon = (Ribbon)d; + if (ribbon.suppressAutomaticStateManagement) + { + return false; + } + + return basevalue; + } + + private static void OnAutoStateManagement(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if ((bool)e.NewValue) + { + ribbon.LoadInitialState(); + } + } + + #endregion + + private class RibbonState : IDisposable + { + private readonly Ribbon ribbon; + + // Name of the isolated storage file + private string isolatedStorageFileName; + private Stream memoryStream; + + public RibbonState(Ribbon ribbon) + { + this.ribbon = ribbon; + this.memoryStream = new MemoryStream(); + } + + /// + /// Gets or sets whether state is loaded + /// + public bool IsStateLoaded { get; private set; } + + /// + /// Gets name of the isolated storage file + /// + private string IsolatedStorageFileName + { + get + { + if (this.isolatedStorageFileName != null) + { + return this.isolatedStorageFileName; + } + + var stringForHash = ""; + var window = Window.GetWindow(this.ribbon); + + if (window != null) + { + stringForHash += "." + window.GetType().FullName; + + if (string.IsNullOrEmpty(window.Name) == false + && window.Name.Trim().Length > 0) + { + stringForHash += "." + window.Name; + } + } + + if (string.IsNullOrEmpty(this.ribbon.Name) == false + && this.ribbon.Name.Trim().Length > 0) + { + stringForHash += "." + this.ribbon.Name; + } + + this.isolatedStorageFileName = "Fluent.Ribbon.State.2.0." + stringForHash.GetHashCode().ToString("X"); + return this.isolatedStorageFileName; + } + } + + public void SaveStateToMemoryStream() + { + this.memoryStream.Position = 0; + this.SaveState(this.memoryStream); + } + + // Saves to Isolated Storage (in user store for domain) + public void SaveStateToIsolatedStorage() + { + // Check whether automatic save is valid now + if (this.ribbon.AutomaticStateManagement == false) + { + Trace.WriteLine(string.Format("State not saved to isolated storage. Because automatic state management is disabled.")); + return; + } + + if (this.IsStateLoaded == false) + { + Trace.WriteLine(string.Format("State not saved to isolated storage. Because state was not loaded before.")); + return; + } + + try + { + var storage = GetIsolatedStorageFile(); + + using (var stream = new IsolatedStorageFileStream(this.IsolatedStorageFileName, FileMode.Create, FileAccess.Write, storage)) + { + this.SaveState(stream); + } + } + catch (Exception ex) + { + Trace.WriteLine(string.Format("Error while trying to save Ribbon state. Error: {0}", ex)); + } + } + + /// + /// Saves state to the given stream + /// + /// Stream + private void SaveState(Stream stream) + { + // Don't save or load state in design mode + if (DesignerProperties.GetIsInDesignMode(this.ribbon)) + { + return; + } + + var builder = new StringBuilder(); + + var isMinimizedSaveState = this.ribbon.IsMinimized; + + // Save Ribbon State + builder.Append(isMinimizedSaveState.ToString(CultureInfo.InvariantCulture)); + builder.Append(','); + builder.Append(this.ribbon.ShowQuickAccessToolBarAboveRibbon.ToString(CultureInfo.InvariantCulture)); + builder.Append('|'); + + // Save QAT items + var paths = new Dictionary(); + this.ribbon.TraverseLogicalTree(this.ribbon, "", paths); + + // Foreach items and see whether path is found for the item + foreach (var element in this.ribbon.quickAccessElements) + { + string path; + var control = element.Key as FrameworkElement; + + if (control != null + && paths.TryGetValue(control, out path)) + { + builder.Append(path); + builder.Append(';'); + } + else + { + // Item is not found in logical tree, output to debug console + var controlName = (control != null && string.IsNullOrEmpty(control.Name) == false) + ? string.Format(CultureInfo.InvariantCulture, " (name of the control is {0})", control.Name) + : string.Empty; + + Debug.WriteLine("Control " + element.Key.GetType().Name + " is not found in logical tree during QAT saving" + controlName); + } + } + + var writer = new StreamWriter(stream); + writer.Write(builder.ToString()); + + writer.Flush(); + } + + public void LoadStateFromMemoryStream() + { + this.memoryStream.Position = 0; + this.LoadState(this.memoryStream); + } + + /// + /// Loads the State from Isolated Storage (in user store for domain) + /// + /// + /// Sets after it's finished to prevent a race condition with saving the state to the MemoryStream. + /// + public void LoadStateFromIsolatedStorage() + { + // Don't save or load state in design mode + if (DesignerProperties.GetIsInDesignMode(this.ribbon)) + { + Trace.WriteLine(string.Format("State not loaded from isolated storage. Because we are in design mode.")); + this.IsStateLoaded = true; + return; + } + + if (this.ribbon.AutomaticStateManagement == false) + { + this.IsStateLoaded = true; + Trace.WriteLine(string.Format("State not loaded from isolated storage. Because automatic state management is disabled.")); + return; + } + + try + { + var storage = GetIsolatedStorageFile(); + if (FileExists(storage, this.IsolatedStorageFileName)) + { + using (var stream = new IsolatedStorageFileStream(this.IsolatedStorageFileName, FileMode.Open, FileAccess.Read, storage)) + { + this.LoadState(stream); + + // Copy loaded state to MemoryStream for temporary storage. + // Temporary storage is used for style changes etc. so we can apply the current state again. + stream.Position = 0; + this.memoryStream.Position = 0; + stream.CopyTo(this.memoryStream); + } + } + } + catch (Exception ex) + { + Trace.WriteLine(string.Format("Error while trying to load Ribbon state. Error: {0}", ex)); + } + + this.IsStateLoaded = true; + } + + /// + /// Loads state from the given stream + /// + /// Stream + private void LoadState(Stream stream) + { + this.ribbon.suppressAutomaticStateManagement = true; + + var reader = new StreamReader(stream); + var splitted = reader.ReadToEnd().Split('|'); + + if (splitted.Length != 2) + { + return; + } + + // Load Ribbon State + var ribbonProperties = splitted[0].Split(','); + + var isMinimized = bool.Parse(ribbonProperties[0]); + + this.ribbon.IsMinimized = isMinimized; + + this.ribbon.ShowQuickAccessToolBarAboveRibbon = bool.Parse(ribbonProperties[1]); + + // Load items + var items = splitted[1].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + + if (this.ribbon.quickAccessToolBar != null) + { + this.ribbon.quickAccessToolBar.Items.Clear(); + } + + this.ribbon.quickAccessElements.Clear(); + + for (var i = 0; i < items.Length; i++) + { + this.ribbon.ParseAndAddToQuickAccessToolBar(items[i]); + } + + // Since application is not fully loaded we have to delay the refresh + this.ribbon.RunInDispatcherAsync(this.ribbon.QuickAccessToolBar.Refresh, DispatcherPriority.Background); + + // Sync QAT menu items + foreach (var menuItem in this.ribbon.QuickAccessItems) + { + menuItem.IsChecked = this.ribbon.IsInQuickAccessToolBar(menuItem.Target); + } + + this.ribbon.suppressAutomaticStateManagement = false; + } + + // Determinates whether the given file exists in the given storage + private static bool FileExists(IsolatedStorageFile storage, string fileName) + { + var files = storage.GetFileNames(fileName); + return files.Length != 0; + } + + // Gets a proper isolated storage file + private static IsolatedStorageFile GetIsolatedStorageFile() + { + try + { + return IsolatedStorageFile.GetUserStoreForDomain(); + } + catch + { + return IsolatedStorageFile.GetUserStoreForAssembly(); + } + } + + /// + /// Resets automatically saved state + /// + public static void ResetState() + { + var storage = GetIsolatedStorageFile(); + + foreach (var filename in storage.GetFileNames("*Fluent.Ribbon.State*")) + { + storage.DeleteFile(filename); + } + } + + private void Dispose(bool disposing) + { + if (disposing == false) + { + return; + } + + if (this.memoryStream != null) + { + this.memoryStream.Dispose(); + } + + this.memoryStream = Stream.Null; + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + } + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonContextualGroupsContainer.cs b/Fluent.Ribbon/Controls/RibbonContextualGroupsContainer.cs similarity index 90% rename from Fluent/Controls/RibbonContextualGroupsContainer.cs rename to Fluent.Ribbon/Controls/RibbonContextualGroupsContainer.cs index c649b25e1..e3c9d155a 100644 --- a/Fluent/Controls/RibbonContextualGroupsContainer.cs +++ b/Fluent.Ribbon/Controls/RibbonContextualGroupsContainer.cs @@ -1,156 +1,139 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Media; - - /// - /// Represents contextual groups container - /// - public class RibbonContextualGroupsContainer : Panel - { - #region Fields - - private readonly List sizes = new List(); - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, positions child elements and determines a size for - /// a System.Windows.FrameworkElement derived class. - /// - /// The final area within the parent that this element should - /// use to arrange itself and its children. - /// The actual size used. - protected override Size ArrangeOverride(Size finalSize) - { - var finalRect = new Rect(finalSize); - var index = 0; - - foreach (UIElement item in this.InternalChildren) - { - finalRect.Width = this.sizes[index].Width;//item.DesiredSize.Width; - finalRect.Height = Math.Max(finalSize.Height, this.sizes[index].Height);//Math.Max(finalSize.Height, item.DesiredSize.Height); - item.Arrange(finalRect); - finalRect.X += this.sizes[index].Width;// item.DesiredSize.Width; - index++; - } - return finalSize; - } - - /// - /// When overridden in a derived class, measures the size in layout required for - /// child elements and determines a size for the System.Windows.FrameworkElement-derived class. - /// - /// The available size that this element can give to child elements. - /// Infinity can be specified as a value to indicate that the element will size to whatever content is available. - /// The size that this element determines it needs during layout, based on its calculations of child element sizes. - protected override Size MeasureOverride(Size availableSize) - { - var x = 0D; - this.sizes.Clear(); - var infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); - - foreach (RibbonContextualTabGroup contextualGroup in this.InternalChildren) - { - // Calculate width of tab items of the group - var tabsWidth = 0D; - - var visibleItems = contextualGroup.Items.Where(group => group.Visibility == Visibility.Visible).ToList(); - - foreach (var item in visibleItems) - { - tabsWidth += item.DesiredSize.Width; - } - - contextualGroup.Measure(infinity); - var groupWidth = contextualGroup.DesiredSize.Width; - - var tabWasChanged = false; - - if (groupWidth > tabsWidth) - { - // If tab's width is less than group's width we have to stretch tabs - var delta = (groupWidth - tabsWidth) / visibleItems.Count; - - foreach (var item in visibleItems) - { - if (item.DesiredWidth == 0) - { - item.DesiredWidth = item.DesiredSize.Width + delta; - item.Measure(new Size(item.DesiredWidth, item.DesiredSize.Height)); - tabWasChanged = true; - } - } - } - - if (tabWasChanged) - { - // If we have changed tabs layout we have - // to invalidate down to RibbonTabsContainer - var visual = visibleItems[0] as Visual; - while (visual != null) - { - var uiElement = visual as UIElement; - if (uiElement != null) - { - if (uiElement is RibbonTabsContainer) - { - uiElement.InvalidateMeasure(); - break; - } - - uiElement.InvalidateMeasure(); - } - - visual = VisualTreeHelper.GetParent(visual) as Visual; - } - - tabsWidth = 0; - - foreach (var item in visibleItems) - { - tabsWidth += item.DesiredSize.Width; - } - } - - // Calc final width and measure the group using it - var finalWidth = tabsWidth; - x += finalWidth; - - if (x > availableSize.Width) - { - finalWidth -= x - availableSize.Width; - x = availableSize.Width; - } - - contextualGroup.Measure(new Size(Math.Max(0, finalWidth), availableSize.Height)); - this.sizes.Add(new Size(Math.Max(0, finalWidth), availableSize.Height)); - } - - var height = availableSize.Height; - if (double.IsPositiveInfinity(height)) - { - height = 0; - } - - return new Size(x, height); - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Media; + + /// + /// Represents contextual groups container + /// + public class RibbonContextualGroupsContainer : Panel + { + private readonly List sizes = new List(); + + /// + /// When overridden in a derived class, positions child elements and determines a size for + /// a System.Windows.FrameworkElement derived class. + /// + /// The final area within the parent that this element should + /// use to arrange itself and its children. + /// The actual size used. + protected override Size ArrangeOverride(Size finalSize) + { + var finalRect = new Rect(finalSize); + var index = 0; + + foreach (UIElement item in this.InternalChildren) + { + finalRect.Width = this.sizes[index].Width;//item.DesiredSize.Width; + finalRect.Height = Math.Max(finalSize.Height, this.sizes[index].Height);//Math.Max(finalSize.Height, item.DesiredSize.Height); + item.Arrange(finalRect); + finalRect.X += this.sizes[index].Width;// item.DesiredSize.Width; + index++; + } + return finalSize; + } + + /// + /// When overridden in a derived class, measures the size in layout required for + /// child elements and determines a size for the System.Windows.FrameworkElement-derived class. + /// + /// The available size that this element can give to child elements. + /// Infinity can be specified as a value to indicate that the element will size to whatever content is available. + /// The size that this element determines it needs during layout, based on its calculations of child element sizes. + protected override Size MeasureOverride(Size availableSize) + { + var x = 0D; + this.sizes.Clear(); + var infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); + + foreach (RibbonContextualTabGroup contextualGroup in this.InternalChildren) + { + // Calculate width of tab items of the group + var tabsWidth = 0D; + + var visibleItems = contextualGroup.Items.Where(group => group.Visibility == Visibility.Visible).ToList(); + + foreach (var item in visibleItems) + { + tabsWidth += item.DesiredSize.Width; + } + + contextualGroup.Measure(infinity); + var groupWidth = contextualGroup.DesiredSize.Width; + + var tabWasChanged = false; + + if (groupWidth > tabsWidth) + { + // If tab's width is less than group's width we have to stretch tabs + var delta = (groupWidth - tabsWidth) / visibleItems.Count; + + foreach (var item in visibleItems) + { + if (item.DesiredWidth == 0) + { + item.DesiredWidth = item.DesiredSize.Width + delta; + item.Measure(new Size(item.DesiredWidth, item.DesiredSize.Height)); + tabWasChanged = true; + } + } + } + + if (tabWasChanged) + { + // If we have changed tabs layout we have + // to invalidate down to RibbonTabsContainer + var visual = visibleItems[0] as Visual; + while (visual != null) + { + var uiElement = visual as UIElement; + if (uiElement != null) + { + if (uiElement is RibbonTabsContainer) + { + uiElement.InvalidateMeasure(); + break; + } + + uiElement.InvalidateMeasure(); + } + + visual = VisualTreeHelper.GetParent(visual) as Visual; + } + + tabsWidth = 0; + + foreach (var item in visibleItems) + { + tabsWidth += item.DesiredSize.Width; + } + } + + // Calc final width and measure the group using it + var finalWidth = tabsWidth; + x += finalWidth; + + if (x > availableSize.Width) + { + finalWidth -= x - availableSize.Width; + x = availableSize.Width; + } + + contextualGroup.Measure(new Size(Math.Max(0, finalWidth), availableSize.Height)); + this.sizes.Add(new Size(Math.Max(0, finalWidth), availableSize.Height)); + } + + var height = availableSize.Height; + if (double.IsPositiveInfinity(height)) + { + height = 0; + } + + return new Size(x, height); + } + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonContextualTabGroup.cs b/Fluent.Ribbon/Controls/RibbonContextualTabGroup.cs similarity index 88% rename from Fluent/Controls/RibbonContextualTabGroup.cs rename to Fluent.Ribbon/Controls/RibbonContextualTabGroup.cs index d3db81276..4ded65332 100644 --- a/Fluent/Controls/RibbonContextualTabGroup.cs +++ b/Fluent.Ribbon/Controls/RibbonContextualTabGroup.cs @@ -1,375 +1,358 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; - -namespace Fluent -{ - /// - /// Represents contextual tab group - /// - public class RibbonContextualTabGroup : Control - { - #region Fields - - // Collection of ribbon tab items - private readonly List items = new List(); - - private Window parentWidow; - - #endregion - - #region Properties - - /// - /// Gets or sets group header - /// - public string Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = - DependencyProperty.Register("Header", typeof(string), typeof(RibbonContextualTabGroup), - new UIPropertyMetadata("RibbonContextualTabGroup", OnHeaderChanged)); - - /// - /// Handles header chages - /// - /// Object - /// The event data. - private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - } - - /// - /// Gets collection of tab items - /// - public List Items - { - get { return this.items; } - } - - /// - /// Gets or sets a value indicating whether parent window is maximized - /// - public bool IsWindowMaximized - { - get { return (bool)this.GetValue(IsWindowMaximizedProperty); } - set { this.SetValue(IsWindowMaximizedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsWindowMaximized. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsWindowMaximizedProperty = - DependencyProperty.Register("IsWindowMaximized", typeof(bool), typeof(RibbonContextualTabGroup), new UIPropertyMetadata(false)); - - /// - /// Gets or sets the visibility this group for internal use (this enables us to hide this group when all items in this group are hidden) - /// - public Visibility InnerVisibility - { - get { return (Visibility)this.GetValue(InnerVisibilityProperty); } - private set { this.SetValue(InnerVisibilityPropertyKey, value); } - } - - private static readonly DependencyPropertyKey InnerVisibilityPropertyKey = - DependencyProperty.RegisterReadOnly("InnerVisibility", typeof(Visibility), typeof(RibbonContextualTabGroup), new UIPropertyMetadata(Visibility.Visible)); - - /// - /// Using a DependencyProperty as the backing store for InnerVisibility. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty InnerVisibilityProperty = InnerVisibilityPropertyKey.DependencyProperty; - - /// - /// Gets the first visible TabItem in this group - /// - public RibbonTabItem FirstVisibleItem - { - get - { - return this.GetFirstVisibleItem(); - } - } - - /// - /// Gets the last visible TabItem in this group - /// - public RibbonTabItem LastVisibleItem - { - get - { - return this.GetLastVisibleItem(); - } - } - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonContextualTabGroup() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new FrameworkPropertyMetadata(typeof(RibbonContextualTabGroup))); - VisibilityProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new PropertyMetadata(Visibility.Collapsed, OnVisibilityChanged)); - StyleProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = ((FrameworkElement)d).TryFindResource(typeof(RibbonContextualTabGroup)); - } - - return basevalue; - } - - /// - /// Handles visibility prioperty changed - /// - /// Object - /// The event data - private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var group = (RibbonContextualTabGroup)d; - - foreach (var tab in group.Items) - { - tab.Visibility = group.Visibility; - } - - group.UpdateInnerVisiblityAndGroupBorders(); - - var titleBar = group.Parent as RibbonTitleBar; - - if (titleBar != null) - { - titleBar.InvalidateMeasure(); - } - } - - /// - /// Default constructor - /// - public RibbonContextualTabGroup() - { - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.parentWidow = Window.GetWindow(this); - - this.SubscribeEvents(); - this.UpdateInnerVisibility(); - - if (this.parentWidow != null) - { - this.IsWindowMaximized = this.parentWidow.WindowState == WindowState.Maximized; - } - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.UnSubscribeEvents(); - - this.parentWidow = null; - } - - private void SubscribeEvents() - { - // Always unsubscribe events to ensure we don't subscribe twice - this.UnSubscribeEvents(); - - if (this.parentWidow != null) - { - this.parentWidow.StateChanged += this.OnParentWindowStateChanged; - } - } - - private void UnSubscribeEvents() - { - if (this.parentWidow != null) - { - this.parentWidow.StateChanged -= this.OnParentWindowStateChanged; - } - } - - #endregion - - #region Internal Methods - - /// - /// Appends tab item - /// - /// Ribbon tab item - internal void AppendTabItem(RibbonTabItem item) - { - this.Items.Add(item); - this.UpdateInnerVisiblityAndGroupBorders(); - } - - /// - /// Removes tab item - /// - /// Ribbon tab item - internal void RemoveTabItem(RibbonTabItem item) - { - this.Items.Remove(item); - this.UpdateInnerVisiblityAndGroupBorders(); - } - - private RibbonTabItem GetFirstVisibleItem() - { - return this.items.FirstOrDefault(item => item.Visibility == Visibility.Visible); - } - - private RibbonTabItem GetLastVisibleItem() - { - return this.items.LastOrDefault(item => item.Visibility == Visibility.Visible); - } - - /// - /// Updates the group border - /// - public void UpdateInnerVisiblityAndGroupBorders() - { - this.UpdateInnerVisibility(); - - var leftset = false; - var rightset = false; - - for (var i = 0; i < this.items.Count; i++) - { - //if (i == 0) items[i].HasLeftGroupBorder = true; - //else items[i].HasLeftGroupBorder = false; - //if (i == items.Count - 1) items[i].HasRightGroupBorder = true; - //else items[i].HasRightGroupBorder = false; - - //Workaround so you can have inivisible Tabs on a Group - if (this.items[i].Visibility == Visibility.Visible - && leftset == false) - { - this.items[i].HasLeftGroupBorder = true; - leftset = true; - } - else - { - this.items[i].HasLeftGroupBorder = false; - } - - if (this.items[this.items.Count - 1 - i].Visibility == Visibility.Visible - && rightset == false) - { - this.items[this.items.Count - 1 - i].HasRightGroupBorder = true; - rightset = true; - } - else - { - this.items[this.items.Count - 1 - i].HasRightGroupBorder = false; - } - } - } - - #endregion - - #region Override - - /// - /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonUp�routed event - /// reaches an element in its route that is derived from this class. Implement this method to - /// add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was released. - protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) - { - var firstVisibleItem = this.FirstVisibleItem; - - if (e.ClickCount == 1 - && firstVisibleItem != null) - { - if (firstVisibleItem.TabControlParent != null) - { - var currentSelectedItem = firstVisibleItem.TabControlParent.SelectedItem as RibbonTabItem; - - if (currentSelectedItem != null) - { - currentSelectedItem.IsSelected = false; - } - } - - e.Handled = true; - - if (firstVisibleItem.TabControlParent != null) - { - if (firstVisibleItem.TabControlParent.IsMinimized) - { - firstVisibleItem.TabControlParent.IsMinimized = false; - } - - firstVisibleItem.IsSelected = true; - } - } - - base.OnMouseLeftButtonUp(e); - } - - /// - /// Raises the MouseDoubleClick routed event - /// - /// The event data - protected override void OnMouseDoubleClick(MouseButtonEventArgs e) - { - base.OnMouseDoubleClick(e); - - if (this.parentWidow == null) - { - return; - } - - this.parentWidow.WindowState = this.parentWidow.WindowState == WindowState.Maximized - ? WindowState.Normal - : WindowState.Maximized; - } - - #endregion - - /// - /// Updates the Visibility of the inner container - /// - private void UpdateInnerVisibility() - { - this.InnerVisibility = this.Visibility == Visibility.Visible && this.Items.Any(item => item.Visibility == Visibility.Visible) ? Visibility.Visible : Visibility.Collapsed; - } - - private void OnParentWindowStateChanged(object sender, EventArgs e) - { - this.IsWindowMaximized = this.parentWidow.WindowState == WindowState.Maximized; - } - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace Fluent +{ + using Fluent.Helpers; + + /// + /// Represents contextual tab group + /// + public class RibbonContextualTabGroup : Control + { + #region Fields + + // Collection of ribbon tab items + private readonly List items = new List(); + + private Window parentWidow; + + #endregion + + #region Properties + + /// + /// Gets or sets group header + /// + public string Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = + DependencyProperty.Register("Header", typeof(string), typeof(RibbonContextualTabGroup), + new UIPropertyMetadata("RibbonContextualTabGroup", OnHeaderChanged)); + + /// + /// Handles header chages + /// + /// Object + /// The event data. + private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Gets collection of tab items + /// + public List Items + { + get { return this.items; } + } + + /// + /// Gets or sets a value indicating whether parent window is maximized + /// + public bool IsWindowMaximized + { + get { return (bool)this.GetValue(IsWindowMaximizedProperty); } + set { this.SetValue(IsWindowMaximizedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsWindowMaximized. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsWindowMaximizedProperty = + DependencyProperty.Register("IsWindowMaximized", typeof(bool), typeof(RibbonContextualTabGroup), new UIPropertyMetadata(false)); + + /// + /// Gets or sets the visibility this group for internal use (this enables us to hide this group when all items in this group are hidden) + /// + public Visibility InnerVisibility + { + get { return (Visibility)this.GetValue(InnerVisibilityProperty); } + private set { this.SetValue(InnerVisibilityPropertyKey, value); } + } + + private static readonly DependencyPropertyKey InnerVisibilityPropertyKey = + DependencyProperty.RegisterReadOnly("InnerVisibility", typeof(Visibility), typeof(RibbonContextualTabGroup), new UIPropertyMetadata(Visibility.Visible)); + + /// + /// Using a DependencyProperty as the backing store for InnerVisibility. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty InnerVisibilityProperty = InnerVisibilityPropertyKey.DependencyProperty; + + /// + /// Gets the first visible TabItem in this group + /// + public RibbonTabItem FirstVisibleItem + { + get + { + return this.GetFirstVisibleItem(); + } + } + + /// + /// Gets the last visible TabItem in this group + /// + public RibbonTabItem LastVisibleItem + { + get + { + return this.GetLastVisibleItem(); + } + } + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonContextualTabGroup() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new FrameworkPropertyMetadata(typeof(RibbonContextualTabGroup))); + VisibilityProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new PropertyMetadata(Visibility.Collapsed, OnVisibilityChanged)); + StyleProperty.OverrideMetadata(typeof(RibbonContextualTabGroup), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = ((FrameworkElement)d).TryFindResource(typeof(RibbonContextualTabGroup)); + } + + return basevalue; + } + + /// + /// Handles visibility prioperty changed + /// + /// Object + /// The event data + private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var group = (RibbonContextualTabGroup)d; + + foreach (var tab in group.Items) + { + tab.Visibility = group.Visibility; + } + + group.UpdateInnerVisiblityAndGroupBorders(); + + var titleBar = group.Parent as RibbonTitleBar; + + if (titleBar != null) + { + titleBar.InvalidateMeasure(); + } + } + + /// + /// Default constructor + /// + public RibbonContextualTabGroup() + { + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.parentWidow = Window.GetWindow(this); + + this.SubscribeEvents(); + this.UpdateInnerVisibility(); + + if (this.parentWidow != null) + { + this.IsWindowMaximized = this.parentWidow.WindowState == WindowState.Maximized; + } + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.UnSubscribeEvents(); + + this.parentWidow = null; + } + + private void SubscribeEvents() + { + // Always unsubscribe events to ensure we don't subscribe twice + this.UnSubscribeEvents(); + + if (this.parentWidow != null) + { + this.parentWidow.StateChanged += this.OnParentWindowStateChanged; + } + } + + private void UnSubscribeEvents() + { + if (this.parentWidow != null) + { + this.parentWidow.StateChanged -= this.OnParentWindowStateChanged; + } + } + + #endregion + + #region Internal Methods + + /// + /// Appends tab item + /// + /// Ribbon tab item + internal void AppendTabItem(RibbonTabItem item) + { + this.Items.Add(item); + this.UpdateInnerVisiblityAndGroupBorders(); + } + + /// + /// Removes tab item + /// + /// Ribbon tab item + internal void RemoveTabItem(RibbonTabItem item) + { + this.Items.Remove(item); + this.UpdateInnerVisiblityAndGroupBorders(); + } + + private RibbonTabItem GetFirstVisibleItem() + { + return this.items.FirstOrDefault(item => item.Visibility == Visibility.Visible); + } + + private RibbonTabItem GetLastVisibleItem() + { + return this.items.LastOrDefault(item => item.Visibility == Visibility.Visible); + } + + /// + /// Updates the group border + /// + public void UpdateInnerVisiblityAndGroupBorders() + { + this.UpdateInnerVisibility(); + + var leftset = false; + var rightset = false; + + for (var i = 0; i < this.items.Count; i++) + { + //if (i == 0) items[i].HasLeftGroupBorder = true; + //else items[i].HasLeftGroupBorder = false; + //if (i == items.Count - 1) items[i].HasRightGroupBorder = true; + //else items[i].HasRightGroupBorder = false; + + //Workaround so you can have inivisible Tabs on a Group + if (this.items[i].Visibility == Visibility.Visible + && leftset == false) + { + this.items[i].HasLeftGroupBorder = true; + leftset = true; + } + else + { + this.items[i].HasLeftGroupBorder = false; + } + + if (this.items[this.items.Count - 1 - i].Visibility == Visibility.Visible + && rightset == false) + { + this.items[this.items.Count - 1 - i].HasRightGroupBorder = true; + rightset = true; + } + else + { + this.items[this.items.Count - 1 - i].HasRightGroupBorder = false; + } + } + } + + #endregion + + #region Override + + /// + /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonUp�routed event + /// reaches an element in its route that is derived from this class. Implement this method to + /// add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was released. + protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) + { + var firstVisibleItem = this.FirstVisibleItem; + + if (e.ClickCount == 1 + && firstVisibleItem != null) + { + var currentSelectedItem = firstVisibleItem.TabControlParent?.SelectedItem as RibbonTabItem; + + if (currentSelectedItem != null) + { + currentSelectedItem.IsSelected = false; + } + + e.Handled = true; + + if (firstVisibleItem.TabControlParent != null) + { + if (firstVisibleItem.TabControlParent.IsMinimized) + { + firstVisibleItem.TabControlParent.IsMinimized = false; + } + + firstVisibleItem.IsSelected = true; + } + } + + base.OnMouseLeftButtonUp(e); + } + + /// + /// Raises the MouseDoubleClick routed event + /// + /// The event data + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + WindowSteeringHelper.HandleMouseLeftButtonDown(e, false, true); + } + + #endregion + + /// + /// Updates the Visibility of the inner container + /// + private void UpdateInnerVisibility() + { + this.InnerVisibility = this.Visibility == Visibility.Visible && this.Items.Any(item => item.Visibility == Visibility.Visible) ? Visibility.Visible : Visibility.Collapsed; + } + + private void OnParentWindowStateChanged(object sender, EventArgs e) + { + this.IsWindowMaximized = this.parentWidow.WindowState == WindowState.Maximized; + } + } +} \ No newline at end of file diff --git a/Fluent/Controls/RibbonControl.cs b/Fluent.Ribbon/Controls/RibbonControl.cs similarity index 91% rename from Fluent/Controls/RibbonControl.cs rename to Fluent.Ribbon/Controls/RibbonControl.cs index 7a60d672d..b15e589e8 100644 --- a/Fluent/Controls/RibbonControl.cs +++ b/Fluent.Ribbon/Controls/RibbonControl.cs @@ -1,519 +1,517 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace Fluent -{ - using Fluent.Internal; - using Fluent.Metro.Native; - - /// - /// Represent base class for Fluent controls - /// - public abstract class RibbonControl : Control, ICommandSource, IQuickAccessItemProvider, IRibbonControl - { - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonControl)); - - #endregion - - #region Header - - /// - /// Gets or sets element header - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = - DependencyProperty.Register("Header", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = - DependencyProperty.Register("Icon", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonControl element = d as RibbonControl; - FrameworkElement oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - FrameworkElement newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - - #endregion - - #region Command - - private bool currentCanExecute = true; - - /// - /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. - /// - [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] - public ICommand Command - { - get - { - return (ICommand)this.GetValue(CommandProperty); - } - set - { - this.SetValue(CommandProperty, value); - } - } - - /// - /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. - /// - [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] - public object CommandParameter - { - get - { - return this.GetValue(CommandParameterProperty); - } - set - { - this.SetValue(CommandParameterProperty, value); - } - } - - /// - /// Gets or sets the element on which to raise the specified command. This is a dependency property. - /// - [Bindable(true), Category("Action")] - public IInputElement CommandTarget - { - get - { - return (IInputElement)this.GetValue(CommandTargetProperty); - } - set - { - this.SetValue(CommandTargetProperty, value); - } - } - - /// - /// Identifies the CommandParameter dependency property. - /// - public static readonly DependencyProperty CommandParameterProperty = ButtonBase.CommandParameterProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null)); - /// - /// Identifies the routed Command dependency property. - /// - public static readonly DependencyProperty CommandProperty = ButtonBase.CommandProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnCommandChanged))); - - /// - /// Identifies the CommandTarget dependency property. - /// - public static readonly DependencyProperty CommandTargetProperty = ButtonBase.CommandTargetProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null)); - - /// - /// Handles Command changed - /// - /// - /// - private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = d as RibbonControl; - - if (control == null) - { - return; - } - - var oldCommand = e.OldValue as ICommand; - if (oldCommand != null) - { - oldCommand.CanExecuteChanged -= control.OnCommandCanExecuteChanged; - } - - var newCommand = e.NewValue as ICommand; - if (newCommand != null) - { - newCommand.CanExecuteChanged += control.OnCommandCanExecuteChanged; - - var routedUiCommand = e.NewValue as RoutedUICommand; - if (routedUiCommand != null - && control.Header == null) - { - control.Header = routedUiCommand.Text; - } - } - - control.UpdateCanExecute(); - } - /// - /// Handles Command CanExecute changed - /// - /// - /// - private void OnCommandCanExecuteChanged(object sender, EventArgs e) - { - this.UpdateCanExecute(); - } - - private void UpdateCanExecute() - { - var canExecute = this.Command != null - && this.CanExecuteCommand(); - - if (this.currentCanExecute != canExecute) - { - this.currentCanExecute = canExecute; - this.CoerceValue(IsEnabledProperty); - } - } - - /// - /// Execute command - /// - protected void ExecuteCommand() - { - CommandHelper.Execute(this.Command, this.CommandParameter, this.CommandTarget); - } - - /// - /// Determines whether the Command can be executed - /// - /// Returns Command CanExecute - protected bool CanExecuteCommand() - { - return CommandHelper.CanExecute(this.Command, this.CommandParameter, this.CommandTarget); - } - - #endregion - - #region IsEnabled - - /// - /// Gets a value that becomes the return - /// value of IsEnabled in derived classes. - /// - /// - /// true if the element is enabled; otherwise, false. - /// - protected override bool IsEnabledCore - { - get - { - return (base.IsEnabledCore && (this.currentCanExecute || this.Command == null)); - } - } - - #endregion - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonControl)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonControl)); - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonControl() - { - Type type = typeof(RibbonControl); - ContextMenuService.Attach(type); - ToolTipService.Attach(type); - } - - /// - /// Default Constructor - /// - protected RibbonControl() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region QuickAccess - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public abstract FrameworkElement CreateQuickAccessItem(); - - /// - /// Binds default properties of control to quick access element - /// - /// Toolbar item - /// Source item - public static void BindQuickAccessItem(FrameworkElement source, FrameworkElement element) - { - Bind(source, element, "DataContext", DataContextProperty, BindingMode.OneWay); - - if (source is ICommandSource) - { - if (source is MenuItem) - { - Bind(source, element, "CommandParameter", ButtonBase.CommandParameterProperty, BindingMode.OneWay); - Bind(source, element, "CommandTarget", System.Windows.Controls.MenuItem.CommandTargetProperty, BindingMode.OneWay); - Bind(source, element, "Command", System.Windows.Controls.MenuItem.CommandProperty, BindingMode.OneWay); - } - else - { - Bind(source, element, "CommandParameter", ButtonBase.CommandParameterProperty, BindingMode.OneWay); - Bind(source, element, "CommandTarget", ButtonBase.CommandTargetProperty, BindingMode.OneWay); - Bind(source, element, "Command", ButtonBase.CommandProperty, BindingMode.OneWay); - } - } - - Bind(source, element, "ToolTip", ToolTipProperty, BindingMode.OneWay); - - Bind(source, element, "FontFamily", FontFamilyProperty, BindingMode.OneWay); - Bind(source, element, "FontSize", FontSizeProperty, BindingMode.OneWay); - Bind(source, element, "FontStretch", FontStretchProperty, BindingMode.OneWay); - Bind(source, element, "FontStyle", FontStyleProperty, BindingMode.OneWay); - Bind(source, element, "FontWeight", FontWeightProperty, BindingMode.OneWay); - - Bind(source, element, "Foreground", ForegroundProperty, BindingMode.OneWay); - Bind(source, element, "IsEnabled", IsEnabledProperty, BindingMode.OneWay); - Bind(source, element, "Opacity", OpacityProperty, BindingMode.OneWay); - Bind(source, element, "SnapsToDevicePixels", SnapsToDevicePixelsProperty, BindingMode.OneWay); - - Bind(source, element, new PropertyPath(FocusManager.IsFocusScopeProperty), FocusManager.IsFocusScopeProperty, BindingMode.OneWay); - - var sourceControl = source as IRibbonControl; - if (sourceControl != null) - { - if (sourceControl.Icon != null) - { - var iconVisual = sourceControl.Icon as Visual; - if (iconVisual != null) - { - var rect = new Rectangle(); - rect.Width = 16; - rect.Height = 16; - rect.Fill = new VisualBrush(iconVisual); - ((IRibbonControl) element).Icon = rect; - } - else - { - Bind(source, element, "Icon", IconProperty, BindingMode.OneWay); - } - } - - if (sourceControl.Header != null) - { - Bind(source, element, "Header", HeaderProperty, BindingMode.OneWay); - } - } - - RibbonProperties.SetSize(element, RibbonControlSize.Small); - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = - DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonControl), new UIPropertyMetadata(true, OnCanAddToQuickAccessToolbarChanged)); - - /// - /// Occurs then CanAddToQuickAccessToolBar property changed - /// - /// - /// - public static void OnCanAddToQuickAccessToolbarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - d.CoerceValue(ContextMenuProperty); - } - - #endregion - - #region Binding - - internal static void Bind(object source, FrameworkElement target, string path, DependencyProperty property, BindingMode mode) - { - Bind(source, target, new PropertyPath(path), property, mode); - } - - internal static void Bind(object source, FrameworkElement target, PropertyPath path, DependencyProperty property, BindingMode mode) - { - var binding = new Binding - { - Path = path, - Source = source, - Mode = mode - }; - target.SetBinding(property, binding); - } - - #endregion - - #region Methods - - /// - /// Handles key tip pressed - /// - public virtual void OnKeyTipPressed() - { - } - - /// - /// Handles back navigation with KeyTips - /// - public virtual void OnKeyTipBack() - { - } - - #endregion - - #region StaticMethods - - /// - /// Returns screen workarea in witch control is placed - /// - /// Control - /// Workarea in witch control is placed - public static Rect GetControlWorkArea(FrameworkElement control) - { - var tabItemPos = control.PointToScreen(new Point(0, 0)); - var tabItemRect = new RECT(); - tabItemRect.left = (int)tabItemPos.X; - tabItemRect.top = (int)tabItemPos.Y; - tabItemRect.right = (int)tabItemPos.X + (int)control.ActualWidth; - tabItemRect.bottom = (int)tabItemPos.Y + (int)control.ActualHeight; - const uint MONITOR_DEFAULTTONEAREST = 0x00000002; - var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); - if (monitor != IntPtr.Zero) - { - var monitorInfo = new MONITORINFO(); - monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); - UnsafeNativeMethods.GetMonitorInfo(monitor, monitorInfo); - return new Rect(monitorInfo.rcWork.left, monitorInfo.rcWork.top, monitorInfo.rcWork.right - monitorInfo.rcWork.left, monitorInfo.rcWork.bottom - monitorInfo.rcWork.top); - } - return new Rect(); - } - - /// - /// Returns monitor in witch control is placed - /// - /// Control - /// Workarea in witch control is placed - public static Rect GetControlMonitor(FrameworkElement control) - { - var tabItemPos = control.PointToScreen(new Point(0, 0)); - var tabItemRect = new RECT(); - tabItemRect.left = (int)tabItemPos.X; - tabItemRect.top = (int)tabItemPos.Y; - tabItemRect.right = (int)tabItemPos.X + (int)control.ActualWidth; - tabItemRect.bottom = (int)tabItemPos.Y + (int)control.ActualHeight; - const uint MONITOR_DEFAULTTONEAREST = 0x00000002; - var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); - if (monitor != IntPtr.Zero) - { - var monitorInfo = new MONITORINFO(); - monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); - UnsafeNativeMethods.GetMonitorInfo(monitor, monitorInfo); - return new Rect(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); - } - return new Rect(); - } - - #endregion - } +using System; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Shapes; + +namespace Fluent +{ + using Fluent.Internal; + using Fluent.Metro.Native; + + /// + /// Represent base class for Fluent controls + /// + public abstract class RibbonControl : Control, ICommandSource, IQuickAccessItemProvider, IRibbonControl + { + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonControl)); + + #endregion + + #region Header + + /// + /// Gets or sets element header + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = + DependencyProperty.Register("Header", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = (RibbonControl)d; + + var oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) + { + element.RemoveLogicalChild(oldElement); + } + + var newElement = e.NewValue as FrameworkElement; + if (newElement != null) + { + element.AddLogicalChild(newElement); + } + } + + #endregion + + #region Command + + private bool currentCanExecute = true; + + /// + /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. + /// + [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] + public ICommand Command + { + get + { + return (ICommand)this.GetValue(CommandProperty); + } + set + { + this.SetValue(CommandProperty, value); + } + } + + /// + /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. + /// + [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] + public object CommandParameter + { + get + { + return this.GetValue(CommandParameterProperty); + } + set + { + this.SetValue(CommandParameterProperty, value); + } + } + + /// + /// Gets or sets the element on which to raise the specified command. This is a dependency property. + /// + [Bindable(true), Category("Action")] + public IInputElement CommandTarget + { + get + { + return (IInputElement)this.GetValue(CommandTargetProperty); + } + set + { + this.SetValue(CommandTargetProperty, value); + } + } + + /// + /// Identifies the CommandParameter dependency property. + /// + public static readonly DependencyProperty CommandParameterProperty = ButtonBase.CommandParameterProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null)); + /// + /// Identifies the routed Command dependency property. + /// + public static readonly DependencyProperty CommandProperty = ButtonBase.CommandProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnCommandChanged))); + + /// + /// Identifies the CommandTarget dependency property. + /// + public static readonly DependencyProperty CommandTargetProperty = ButtonBase.CommandTargetProperty.AddOwner(typeof(RibbonControl), new FrameworkPropertyMetadata(null)); + + /// + /// Handles Command changed + /// + /// + /// + private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = d as RibbonControl; + + if (control == null) + { + return; + } + + var oldCommand = e.OldValue as ICommand; + if (oldCommand != null) + { + oldCommand.CanExecuteChanged -= control.OnCommandCanExecuteChanged; + } + + var newCommand = e.NewValue as ICommand; + if (newCommand != null) + { + newCommand.CanExecuteChanged += control.OnCommandCanExecuteChanged; + + var routedUiCommand = e.NewValue as RoutedUICommand; + if (routedUiCommand != null + && control.Header == null) + { + control.Header = routedUiCommand.Text; + } + } + + control.UpdateCanExecute(); + } + /// + /// Handles Command CanExecute changed + /// + /// + /// + private void OnCommandCanExecuteChanged(object sender, EventArgs e) + { + this.UpdateCanExecute(); + } + + private void UpdateCanExecute() + { + var canExecute = this.Command != null + && this.CanExecuteCommand(); + + if (this.currentCanExecute != canExecute) + { + this.currentCanExecute = canExecute; + this.CoerceValue(IsEnabledProperty); + } + } + + /// + /// Execute command + /// + protected void ExecuteCommand() + { + CommandHelper.Execute(this.Command, this.CommandParameter, this.CommandTarget); + } + + /// + /// Determines whether the Command can be executed + /// + /// Returns Command CanExecute + protected bool CanExecuteCommand() + { + return CommandHelper.CanExecute(this.Command, this.CommandParameter, this.CommandTarget); + } + + #endregion + + #region IsEnabled + + /// + /// Gets a value that becomes the return + /// value of IsEnabled in derived classes. + /// + /// + /// true if the element is enabled; otherwise, false. + /// + protected override bool IsEnabledCore + { + get + { + return (base.IsEnabledCore && (this.currentCanExecute || this.Command == null)); + } + } + + #endregion + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonControl)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonControl)); + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonControl() + { + Type type = typeof(RibbonControl); + ContextMenuService.Attach(type); + ToolTipService.Attach(type); + } + + /// + /// Default Constructor + /// + protected RibbonControl() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region QuickAccess + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public abstract FrameworkElement CreateQuickAccessItem(); + + /// + /// Binds default properties of control to quick access element + /// + /// Toolbar item + /// Source item + public static void BindQuickAccessItem(FrameworkElement source, FrameworkElement element) + { + Bind(source, element, "DataContext", DataContextProperty, BindingMode.OneWay); + + if (source is ICommandSource) + { + if (source is MenuItem) + { + Bind(source, element, "CommandParameter", ButtonBase.CommandParameterProperty, BindingMode.OneWay); + Bind(source, element, "CommandTarget", System.Windows.Controls.MenuItem.CommandTargetProperty, BindingMode.OneWay); + Bind(source, element, "Command", System.Windows.Controls.MenuItem.CommandProperty, BindingMode.OneWay); + } + else + { + Bind(source, element, "CommandParameter", ButtonBase.CommandParameterProperty, BindingMode.OneWay); + Bind(source, element, "CommandTarget", ButtonBase.CommandTargetProperty, BindingMode.OneWay); + Bind(source, element, "Command", ButtonBase.CommandProperty, BindingMode.OneWay); + } + } + + Bind(source, element, "ToolTip", ToolTipProperty, BindingMode.OneWay); + + Bind(source, element, "FontFamily", FontFamilyProperty, BindingMode.OneWay); + Bind(source, element, "FontSize", FontSizeProperty, BindingMode.OneWay); + Bind(source, element, "FontStretch", FontStretchProperty, BindingMode.OneWay); + Bind(source, element, "FontStyle", FontStyleProperty, BindingMode.OneWay); + Bind(source, element, "FontWeight", FontWeightProperty, BindingMode.OneWay); + + Bind(source, element, "Foreground", ForegroundProperty, BindingMode.OneWay); + Bind(source, element, "IsEnabled", IsEnabledProperty, BindingMode.OneWay); + Bind(source, element, "Opacity", OpacityProperty, BindingMode.OneWay); + Bind(source, element, "SnapsToDevicePixels", SnapsToDevicePixelsProperty, BindingMode.OneWay); + + Bind(source, element, new PropertyPath(FocusManager.IsFocusScopeProperty), FocusManager.IsFocusScopeProperty, BindingMode.OneWay); + + var sourceControl = source as IRibbonControl; + if (sourceControl != null) + { + if (sourceControl.Icon != null) + { + var iconVisual = sourceControl.Icon as Visual; + if (iconVisual != null) + { + var rect = new Rectangle(); + rect.Width = 16; + rect.Height = 16; + rect.Fill = new VisualBrush(iconVisual); + ((IRibbonControl)element).Icon = rect; + } + else + { + Bind(source, element, "Icon", IconProperty, BindingMode.OneWay); + } + } + + if (sourceControl.Header != null) + { + Bind(source, element, "Header", HeaderProperty, BindingMode.OneWay); + } + } + + RibbonProperties.SetSize(element, RibbonControlSize.Small); + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = + DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonControl), new UIPropertyMetadata(true, OnCanAddToQuickAccessToolbarChanged)); + + /// + /// Occurs then CanAddToQuickAccessToolBar property changed + /// + /// + /// + public static void OnCanAddToQuickAccessToolbarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.CoerceValue(ContextMenuProperty); + } + + #endregion + + #region Binding + + internal static void Bind(object source, FrameworkElement target, string path, DependencyProperty property, BindingMode mode) + { + Bind(source, target, new PropertyPath(path), property, mode); + } + + internal static void Bind(object source, FrameworkElement target, PropertyPath path, DependencyProperty property, BindingMode mode) + { + var binding = new Binding + { + Path = path, + Source = source, + Mode = mode + }; + target.SetBinding(property, binding); + } + + #endregion + + #region Methods + + /// + /// Handles key tip pressed + /// + public virtual void OnKeyTipPressed() + { + } + + /// + /// Handles back navigation with KeyTips + /// + public virtual void OnKeyTipBack() + { + } + + #endregion + + #region StaticMethods + + /// + /// Returns screen workarea in witch control is placed + /// + /// Control + /// Workarea in witch control is placed + public static Rect GetControlWorkArea(FrameworkElement control) + { + var tabItemPos = control.PointToScreen(new Point(0, 0)); + var tabItemRect = new RECT(); + tabItemRect.left = (int)tabItemPos.X; + tabItemRect.top = (int)tabItemPos.Y; + tabItemRect.right = (int)tabItemPos.X + (int)control.ActualWidth; + tabItemRect.bottom = (int)tabItemPos.Y + (int)control.ActualHeight; + const uint MONITOR_DEFAULTTONEAREST = 0x00000002; + var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); + if (monitor != IntPtr.Zero) + { + var monitorInfo = new MONITORINFO(); + monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); + NativeMethods.GetMonitorInfo(monitor, monitorInfo); + return new Rect(monitorInfo.rcWork.left, monitorInfo.rcWork.top, monitorInfo.rcWork.right - monitorInfo.rcWork.left, monitorInfo.rcWork.bottom - monitorInfo.rcWork.top); + } + return new Rect(); + } + + /// + /// Returns monitor in witch control is placed + /// + /// Control + /// Workarea in witch control is placed + public static Rect GetControlMonitor(FrameworkElement control) + { + var tabItemPos = control.PointToScreen(new Point(0, 0)); + var tabItemRect = new RECT(); + tabItemRect.left = (int)tabItemPos.X; + tabItemRect.top = (int)tabItemPos.Y; + tabItemRect.right = (int)tabItemPos.X + (int)control.ActualWidth; + tabItemRect.bottom = (int)tabItemPos.Y + (int)control.ActualHeight; + const uint MONITOR_DEFAULTTONEAREST = 0x00000002; + var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); + if (monitor != IntPtr.Zero) + { + var monitorInfo = new MONITORINFO(); + monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); + NativeMethods.GetMonitorInfo(monitor, monitorInfo); + return new Rect(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top); + } + return new Rect(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonGroupBox.cs b/Fluent.Ribbon/Controls/RibbonGroupBox.cs similarity index 95% rename from Fluent/Controls/RibbonGroupBox.cs rename to Fluent.Ribbon/Controls/RibbonGroupBox.cs index f3b495714..ccec98f62 100644 --- a/Fluent/Controls/RibbonGroupBox.cs +++ b/Fluent.Ribbon/Controls/RibbonGroupBox.cs @@ -1,1139 +1,1128 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; - -namespace Fluent -{ - using Fluent.Internal; - - /// - /// RibbonGroup represents a logical group of controls as they appear on - /// a RibbonTab. These groups can resize its content - /// - [TemplatePart(Name = "PART_DialogLauncherButton", Type = typeof(Button))] - [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] - [TemplatePart(Name = "PART_UpPanel", Type = typeof(Panel))] - public class RibbonGroupBox : ItemsControl, IQuickAccessItemProvider, IDropDownControl, IKeyTipedControl, IHeaderedControl - { - #region Fields - - // up part - private Panel upPanel; - - private Panel parentPanel; - - // Freezed image (created during snapping) - private Image snappedImage; - - // Is visual currently snapped - private bool isSnapped; - - private readonly ItemContainerGeneratorAction updateChildSizesItemContainerGeneratorAction; - - #endregion - - #region Properties - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonGroupBox)); - - #endregion - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup { get; private set; } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - #region State - - /// - /// Gets or sets the current state of the group - /// - public RibbonGroupBoxState State - { - get { return (RibbonGroupBoxState)this.GetValue(StateProperty); } - set { this.SetValue(StateProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for State. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty StateProperty = - DependencyProperty.Register("State", typeof(RibbonGroupBoxState), typeof(RibbonGroupBox), new UIPropertyMetadata(RibbonGroupBoxState.Large, StatePropertyChanged)); - - /// - /// On state property changed - /// - /// Object - /// The event data - static void StatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbonGroupBox = (RibbonGroupBox)d; - ribbonGroupBox.updateChildSizesItemContainerGeneratorAction.QueueAction(); - } - - private void UpdateChildSizes() - { - var groupBoxState = this.State == RibbonGroupBoxState.QuickAccess - ? RibbonGroupBoxState.Collapsed - : this.State; - - foreach (var item in this.Items) - { - var element = this.ItemContainerGenerator.ContainerFromItem(item); - - if (element == null) - { - continue; - } - - RibbonProperties.SetAppropriateSize(element, groupBoxState); - } - } - - #endregion - - #region Scale - - // Current scale index - private int scale; - - /// - /// Gets or sets scale index (for internal IRibbonScalableControl) - /// - internal int Scale - { - get { return this.scale; } - set - { - var difference = value - this.scale; - this.scale = value; - - for (var i = 0; i < Math.Abs(difference); i++) - { - if (difference > 0) - { - this.IncreaseScalableElement(); - } - else - { - this.DecreaseScalableElement(); - } - } - } - } - - // Finds and increase size of all scalable elements in the given group box - private void IncreaseScalableElement() - { - foreach (var item in this.Items) - { - var scalableRibbonControl = item as IScalableRibbonControl; - if (scalableRibbonControl == null) - { - continue; - } - scalableRibbonControl.Enlarge(); - } - } - - private void OnScalableControlScaled(object sender, EventArgs e) - { - this.TryClearCache(); - } - - private void TryClearCache() - { - if (!this.SuppressCacheReseting) - { - this.cachedMeasures.Clear(); - } - } - - /// - /// Gets or sets whether to reset cache when scalable control is scaled - /// - internal bool SuppressCacheReseting { get; set; } - - // Finds and decrease size of all scalable elements in the given group box - private void DecreaseScalableElement() - { - foreach (object item in this.Items) - { - IScalableRibbonControl scalableRibbonControl = item as IScalableRibbonControl; - if (scalableRibbonControl == null) continue; - scalableRibbonControl.Reduce(); - } - } - - private void UpdateScalableControlSubscribing() - { - this.UpdateScalableControlSubscribing(true); - } - - private void UpdateScalableControlSubscribing(bool registerEvents) - { - foreach (var scalableRibbonControl in this.Items.OfType()) - { - // Always unregister first to ensure that we don't subscribe twice - scalableRibbonControl.Scaled -= this.OnScalableControlScaled; - - if (registerEvents) - { - scalableRibbonControl.Scaled += this.OnScalableControlScaled; - } - } - } - - #endregion - - #region Header - - /// - /// Gets or sets group box header - /// - public string Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = - DependencyProperty.Register("Header", typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata()); - - object IHeaderedControl.Header - { - get { return this.Header; } - - set { this.Header = (string)value; } - } - - #endregion - - #region IsLauncherVisible - - /// - /// Gets or sets dialog launcher button visibility - /// - public bool IsLauncherVisible - { - get { return (bool)this.GetValue(IsLauncherVisibleProperty); } - set { this.SetValue(IsLauncherVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsLauncherVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsLauncherVisibleProperty = - DependencyProperty.Register("IsLauncherVisible", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(false)); - - #endregion - - #region LauncherKeys - - /// - /// Gets or sets key tip for dialog launcher button - /// - [DisplayName("DialogLauncher Keys"), - Category("KeyTips"), - Description("Key tip keys for dialog launcher button")] - public string LauncherKeys - { - get { return (string)this.GetValue(DialogLauncherButtonKeyTipKeysProperty); } - set { this.SetValue(DialogLauncherButtonKeyTipKeysProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for - /// LauncherKeys. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DialogLauncherButtonKeyTipKeysProperty = - DependencyProperty.Register("LauncherKeys", - typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnDialogLauncherButtonKeyTipKeysChanged)); - - static void OnDialogLauncherButtonKeyTipKeysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonGroupBox ribbonGroupBox = (RibbonGroupBox)d; - if (ribbonGroupBox.LauncherButton != null) - { - ribbonGroupBox.LauncherButton.KeyTip = (string)e.NewValue; - } - } - - #endregion - - #region LauncherIcon - - /// - /// Gets or sets launcher button icon - /// - public object LauncherIcon - { - get { return (ImageSource)this.GetValue(LauncherIconProperty); } - set { this.SetValue(LauncherIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for LauncherIcon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LauncherIconProperty = - DependencyProperty.Register("LauncherIcon", typeof(object), typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged)); - - #endregion - - #region LauncherIcon - - /// - /// Gets or sets launcher button text - /// - public string LauncherText - { - get { return (string)this.GetValue(LauncherTextProperty); } - set { this.SetValue(LauncherTextProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for LauncherIcon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LauncherTextProperty = - DependencyProperty.Register("LauncherText", typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); - - #endregion - - #region LauncherCommand - - /// - /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. - /// - [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] - public ICommand LauncherCommand - { - get - { - return (ICommand)this.GetValue(LauncherCommandProperty); - } - set - { - this.SetValue(LauncherCommandProperty, value); - } - } - - /// - /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. - /// - [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] - public object LauncherCommandParameter - { - get - { - return this.GetValue(LauncherCommandParameterProperty); - } - set - { - this.SetValue(LauncherCommandParameterProperty, value); - } - } - - /// - /// Gets or sets the element on which to raise the specified command. This is a dependency property. - /// - [Bindable(true), Category("Action")] - public IInputElement LauncherCommandTarget - { - get - { - return (IInputElement)this.GetValue(LauncherCommandTargetProperty); - } - set - { - this.SetValue(LauncherCommandTargetProperty, value); - } - } - - /// - /// Identifies the System.Windows.Controls.Primitives.ButtonBase.CommandParameter dependency property. - /// - public static readonly DependencyProperty LauncherCommandParameterProperty = DependencyProperty.Register("LauncherCommandParameter", typeof(object), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); - /// - /// Identifies the routed System.Windows.Controls.Primitives.ButtonBase.Command dependency property. - /// - public static readonly DependencyProperty LauncherCommandProperty = DependencyProperty.Register("LauncherCommand", typeof(ICommand), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); - - /// - /// Identifies the System.Windows.Controls.Primitives.ButtonBase.CommandTarget dependency property. - /// - public static readonly DependencyProperty LauncherCommandTargetProperty = DependencyProperty.Register("LauncherCommandTarget", typeof(IInputElement), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); - - #endregion - - #region LauncherToolTip - - /// - /// Gets or sets launcher button tooltip - /// - public object LauncherToolTip - { - get { return (object)this.GetValue(LauncherToolTipProperty); } - set { this.SetValue(LauncherToolTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for LauncherToolTip. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LauncherToolTipProperty = - DependencyProperty.Register("LauncherToolTip", typeof(object), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); - - - - #endregion - - #region IsLauncherEnabled - - /// - /// Gets or sets whether launcher button is enabled - /// - public bool IsLauncherEnabled - { - get { return (bool)this.GetValue(IsLauncherEnabledProperty); } - set { this.SetValue(IsLauncherEnabledProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsLauncherEnabled. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsLauncherEnabledProperty = - DependencyProperty.Register("IsLauncherEnabled", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true)); - - #endregion - - #region LauncherButton - - /// - /// Gets launcher button - /// - public Button LauncherButton - { - get { return (Button)this.GetValue(LauncherButtonProperty); } - private set { this.SetValue(LauncherButtonPropertyKey, value); } - } - - private static readonly DependencyPropertyKey LauncherButtonPropertyKey = - DependencyProperty.RegisterReadOnly("LauncherButton", typeof(Button), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for LauncherButton. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LauncherButtonProperty = LauncherButtonPropertyKey.DependencyProperty; - - #endregion - - #region IsOpen - - /// - /// Gets or sets drop down popup visibility - /// - public bool IsDropDownOpen - { - get { return (bool)this.GetValue(IsDropDownOpenProperty); } - set { this.SetValue(IsDropDownOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(false, OnIsOpenChanged, CoerceIsDropDownOpen)); - - private static object CoerceIsDropDownOpen(DependencyObject d, object basevalue) - { - RibbonGroupBox box = d as RibbonGroupBox; - if ((box.State != RibbonGroupBoxState.Collapsed) && (box.State != RibbonGroupBoxState.QuickAccess)) return false; - return basevalue; - } - - #endregion - - #region LogicalChildren - - /// - /// Gets an enumerator for the logical child objects of - /// the System.Windows.Controls.ItemsControl object. - /// - protected override IEnumerator LogicalChildren - { - get - { - foreach (var item in this.Items) - { - yield return item; - } - - if (this.LauncherButton != null) - { - yield return this.LauncherButton; - } - } - } - - #endregion - - #region Icon - - /// - /// Gets or sets icon - /// - public object Icon - //public ImageSource Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = - RibbonControl.IconProperty.AddOwner(typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged)); - - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonGroupBox element = d as RibbonGroupBox; - FrameworkElement oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - FrameworkElement newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - - #endregion - - #endregion - - #region Events - - /// - /// Dialog launcher btton click event - /// - public event RoutedEventHandler LauncherClick; - - /// - /// Occurs when context menu is opened - /// - public event EventHandler DropDownOpened; - - /// - /// Occurs when context menu is closed - /// - public event EventHandler DropDownClosed; - - #endregion - - #region Initialize - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonGroupBox() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(typeof(RibbonGroupBox))); - VisibilityProperty.AddOwner(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(OnVisibilityChanged)); - - PopupService.Attach(typeof(RibbonGroupBox)); - StyleProperty.OverrideMetadata(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - - ContextMenuService.Attach(typeof(RibbonGroupBox)); - } - - // Coerce object style - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonGroupBox)); - } - - return basevalue; - } - - // Handles visibility changed - private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var box = (d as RibbonGroupBox); - if (box != null) box.ClearCache(); - } - - /// - /// Default constructor - /// - public RibbonGroupBox() - { - this.ToolTip = new ToolTip(); - ((ToolTip)this.ToolTip).Template = null; - this.CoerceValue(ContextMenuProperty); - this.Focusable = false; - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - - this.updateChildSizesItemContainerGeneratorAction = new ItemContainerGeneratorAction(this.ItemContainerGenerator, this.UpdateChildSizes); - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.SubscribeEvents(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.UnSubscribeEvents(); - } - - private void SubscribeEvents() - { - // Always unsubscribe events to ensure we don't subscribe twice - this.UnSubscribeEvents(); - - this.UpdateScalableControlSubscribing(); - - if (this.LauncherButton != null) - { - this.LauncherButton.Click += this.OnDialogLauncherButtonClick; - } - - if (this.DropDownPopup != null) - { - this.DropDownPopup.Opened += this.OnPopupOpened; - this.DropDownPopup.Closed += this.OnPopupClosed; - } - } - - private void UnSubscribeEvents() - { - this.UpdateScalableControlSubscribing(false); - - if (this.LauncherButton != null) - { - this.LauncherButton.Click -= this.OnDialogLauncherButtonClick; - } - - if (this.DropDownPopup != null) - { - this.DropDownPopup.Opened -= this.OnPopupOpened; - this.DropDownPopup.Closed -= this.OnPopupClosed; - } - } - - #endregion - - #region Methods - - /// - /// Gets a panel with items - /// - /// - internal Panel GetPanel() { return this.upPanel; } - - /// - /// Gets cmmon layout root for popup and groupbox - /// - /// - internal Panel GetLayoutRoot() { return this.parentPanel; } - - #endregion - - #region Snapping - - /// - /// Snaps / Unsnaps the Visual - /// (remove visuals and substitute with freezed image) - /// - public bool IsSnapped - { - get - { - return this.isSnapped; - } - set - { - if (value == this.isSnapped) - { - return; - } - - if (value) - { - if (this.IsVisible) - { - // Render the freezed image - var renderTargetBitmap = new RenderTargetBitmap((int)this.ActualWidth, (int)this.ActualHeight, 96, 96, PixelFormats.Pbgra32); - renderTargetBitmap.Render((Visual)VisualTreeHelper.GetChild(this, 0)); - this.snappedImage.FlowDirection = this.FlowDirection; - this.snappedImage.Source = renderTargetBitmap; - this.snappedImage.Width = this.ActualWidth; - this.snappedImage.Height = this.ActualHeight; - this.snappedImage.Visibility = Visibility.Visible; - this.isSnapped = true; - } - } - else if (this.snappedImage != null) - { - // Clean up - this.snappedImage.Visibility = Visibility.Collapsed; - this.isSnapped = false; - } - - this.InvalidateVisual(); - } - } - - #endregion - - #region Caching - - // Pair of chached states - struct StateScale - { - public RibbonGroupBoxState State; - public int Scale; - } - - // Cache - readonly Dictionary cachedMeasures = new Dictionary(); - - /// - /// Gets or sets intermediate state of the group box - /// - internal RibbonGroupBoxState StateIntermediate - { - get; - set; - } - - /// - /// Gets or sets intermediate scale of the group box - /// - internal int ScaleIntermediate - { - get; - set; - } - - /// - /// Gets intermediate desired size - /// - internal Size DesiredSizeIntermediate - { - get - { - Size result; - var stateScale = this.GetCurrentIntermediateStateScale(); - - if (this.cachedMeasures.TryGetValue(stateScale, out result) == false) - { - this.SuppressCacheReseting = true; - this.UpdateScalableControlSubscribing(); - - // Get desired size for these values - var backupState = this.State; - var backupScale = this.Scale; - this.State = this.StateIntermediate; - this.Scale = this.ScaleIntermediate; - this.InvalidateLayout(); - this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - this.cachedMeasures.Add(stateScale, this.DesiredSize); - result = this.DesiredSize; - - // Rollback changes - this.State = backupState; - this.Scale = backupScale; - this.InvalidateLayout(); - this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - - this.SuppressCacheReseting = false; - } - - return result; - } - } - - /// - /// Clears cache - /// - public void ClearCache() - { - this.cachedMeasures.Clear(); - } - - /// - /// Invalidates layout (with children) - /// - internal void InvalidateLayout() - { - InvalidateMeasureRecursive(this); - } - - private static void InvalidateMeasureRecursive(UIElement element) - { - if (element == null) - { - return; - } - - element.InvalidateMeasure(); - - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) - { - var child = VisualTreeHelper.GetChild(element, i) as UIElement; - - if (child == null) - { - continue; - } - - InvalidateMeasureRecursive(child); - } - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code - /// or internal processes call System.Windows.FrameworkElement.ApplyTemplate(). - /// - public override void OnApplyTemplate() - { - this.UnSubscribeEvents(); - - // Clear cache - this.cachedMeasures.Clear(); - - this.LauncherButton = this.GetTemplateChild("PART_DialogLauncherButton") as Button; - - if (this.LauncherButton != null) - { - if (this.LauncherKeys != null) - { - this.LauncherButton.KeyTip = this.LauncherKeys; - } - } - - this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup; - - this.upPanel = this.GetTemplateChild("PART_UpPanel") as Panel; - this.parentPanel = this.GetTemplateChild("PART_ParentPanel") as Panel; - - this.snappedImage = this.GetTemplateChild("PART_SnappedImage") as Image; - - this.SubscribeEvents(); - } - - private void OnPopupOpened(object sender, EventArgs e) - { - if (this.DropDownOpened != null) this.DropDownOpened(this, e); - } - - private void OnPopupClosed(object sender, EventArgs e) - { - if (this.DropDownClosed != null) this.DropDownClosed(this, e); - } - - /// - /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDown - /// event reaches an element in its route that is derived from this class. - /// Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - if (e.Source != this - || this.DropDownPopup == null) - { - return; - } - - if (this.State == RibbonGroupBoxState.Collapsed - || this.State == RibbonGroupBoxState.QuickAccess) - { - e.Handled = true; - - if (!this.IsDropDownOpen) - { - this.IsDropDownOpen = true; - } - else - { - PopupService.RaiseDismissPopupEventAsync(this, DismissPopupMode.MouseNotOver); - } - } - } - - /// - /// Supports layout behavior when a child element is resized. - /// - /// The child element that is being resized. - protected override void OnChildDesiredSizeChanged(UIElement child) - { - base.OnChildDesiredSizeChanged(child); - - this.cachedMeasures.Remove(this.GetCurrentIntermediateStateScale()); - } - - private StateScale GetCurrentIntermediateStateScale() - { - var stateScale = new StateScale - { - Scale = this.ScaleIntermediate, - State = this.StateIntermediate - }; - return stateScale; - } - - #endregion - - #region Event Handling - - /// - /// Dialog launcher button click handler - /// - /// Sender - /// the event data - private void OnDialogLauncherButtonClick(object sender, RoutedEventArgs e) - { - if (this.LauncherClick != null) - { - this.LauncherClick(this, e); - } - } - - // Handles popup closing - private void OnRibbonGroupBoxPopupClosing() - { - //IsHitTestVisible = true; - if (Mouse.Captured == this) - { - Mouse.Capture(null); - } - } - - // handles popup opening - private void OnRibbonGroupBoxPopupOpening() - { - //IsHitTestVisible = false; - Mouse.Capture(this, CaptureMode.SubTree); - } - - /// - /// Handles IsOpen propertyu changes - /// - /// Object - /// The event data - private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbon = (RibbonGroupBox)d; - - if (ribbon.IsDropDownOpen) - { - ribbon.OnRibbonGroupBoxPopupOpening(); - } - else - { - ribbon.OnRibbonGroupBoxPopupClosing(); - } - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public FrameworkElement CreateQuickAccessItem() - { - var groupBox = new RibbonGroupBox(); - - RibbonControl.BindQuickAccessItem(this, groupBox); - - groupBox.DropDownOpened += this.OnQuickAccessOpened; - groupBox.DropDownClosed += this.OnQuickAccessClosed; - - groupBox.State = RibbonGroupBoxState.QuickAccess; - - RibbonControl.Bind(this, groupBox, "ItemTemplateSelector", ItemTemplateSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "ItemsSource", ItemsSourceProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherCommandParameter", LauncherCommandParameterProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherCommand", LauncherCommandProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherCommandTarget", LauncherCommandTargetProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherIcon", LauncherIconProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherText", LauncherTextProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "LauncherToolTip", LauncherToolTipProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "IsLauncherEnabled", IsLauncherEnabledProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "IsLauncherVisible", IsLauncherVisibleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, groupBox, "DialogLauncherButtonKeyTipKeys", DialogLauncherButtonKeyTipKeysProperty, BindingMode.OneWay); - groupBox.LauncherClick += this.LauncherClick; - - var toolTip = this.ToolTip as ToolTip; - if ((toolTip == null || toolTip.ToolTip == null) && this.Header != null) - { - RibbonControl.Bind(this, groupBox, "Header", ToolTipProperty, BindingMode.OneWay); - } - - if (this.Icon != null) - { - var iconVisual = this.Icon as Visual; - if (iconVisual != null) - { - var rect = new Rectangle - { - Width = 16, - Height = 16, - Fill = new VisualBrush(iconVisual) - }; - groupBox.Icon = rect; - } - else - { - RibbonControl.Bind(this, groupBox, "Icon", RibbonControl.IconProperty, BindingMode.OneWay); - } - } - - if (this.Header != null) - { - RibbonControl.Bind(this, groupBox, "Header", RibbonControl.HeaderProperty, BindingMode.OneWay); - } - - return groupBox; - } - - private void OnQuickAccessOpened(object sender, EventArgs e) - { - if (!this.IsDropDownOpen - && !this.IsSnapped) - { - var groupBox = sender as RibbonGroupBox; - // Save state - this.IsSnapped = true; - - if (this.ItemsSource == null) - { - for (var i = 0; i < this.Items.Count; i++) - { - var item = this.Items[0]; - this.Items.Remove(item); - groupBox.Items.Add(item); - i--; - } - } - } - } - - private void OnQuickAccessClosed(object sender, EventArgs e) - { - var groupBox = sender as RibbonGroupBox; - - if (this.ItemsSource == null) - { - for (var i = 0; i < groupBox.Items.Count; i++) - { - var item = groupBox.Items[0]; - groupBox.Items.Remove(item); - this.Items.Add(item); - i--; - } - } - - this.IsSnapped = false; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = - DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IKeyTipedControl - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - if (this.State == RibbonGroupBoxState.Collapsed - || this.State == RibbonGroupBoxState.QuickAccess) - { - this.IsDropDownOpen = true; - } - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - this.IsDropDownOpen = false; - } - - #endregion - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Fluent +{ + using Fluent.Internal; + + /// + /// RibbonGroup represents a logical group of controls as they appear on + /// a RibbonTab. These groups can resize its content + /// + [TemplatePart(Name = "PART_DialogLauncherButton", Type = typeof(Button))] + [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] + [TemplatePart(Name = "PART_UpPanel", Type = typeof(Panel))] + public class RibbonGroupBox : ItemsControl, IQuickAccessItemProvider, IDropDownControl, IKeyTipedControl, IHeaderedControl + { + #region Fields + + // up part + private Panel upPanel; + + private Panel parentPanel; + + // Freezed image (created during snapping) + private Image snappedImage; + + // Is visual currently snapped + private bool isSnapped; + + private readonly ItemContainerGeneratorAction updateChildSizesItemContainerGeneratorAction; + + #endregion + + #region Properties + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonGroupBox)); + + #endregion + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup { get; private set; } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + #region State + + /// + /// Gets or sets the current state of the group + /// + public RibbonGroupBoxState State + { + get { return (RibbonGroupBoxState)this.GetValue(StateProperty); } + set { this.SetValue(StateProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for State. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty StateProperty = + DependencyProperty.Register("State", typeof(RibbonGroupBoxState), typeof(RibbonGroupBox), new UIPropertyMetadata(RibbonGroupBoxState.Large, StatePropertyChanged)); + + /// + /// On state property changed + /// + /// Object + /// The event data + static void StatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbonGroupBox = (RibbonGroupBox)d; + ribbonGroupBox.updateChildSizesItemContainerGeneratorAction.QueueAction(); + } + + private void UpdateChildSizes() + { + var groupBoxState = this.State == RibbonGroupBoxState.QuickAccess + ? RibbonGroupBoxState.Collapsed + : this.State; + + foreach (var item in this.Items) + { + var element = this.ItemContainerGenerator.ContainerFromItem(item); + + if (element == null) + { + continue; + } + + RibbonProperties.SetAppropriateSize(element, groupBoxState); + } + } + + #endregion + + #region Scale + + // Current scale index + private int scale; + + /// + /// Gets or sets scale index (for internal IRibbonScalableControl) + /// + internal int Scale + { + get { return this.scale; } + set + { + var difference = value - this.scale; + this.scale = value; + + for (var i = 0; i < Math.Abs(difference); i++) + { + if (difference > 0) + { + this.IncreaseScalableElement(); + } + else + { + this.DecreaseScalableElement(); + } + } + } + } + + // Finds and increase size of all scalable elements in the given group box + private void IncreaseScalableElement() + { + foreach (var item in this.Items) + { + var scalableRibbonControl = item as IScalableRibbonControl; + if (scalableRibbonControl == null) + { + continue; + } + scalableRibbonControl.Enlarge(); + } + } + + private void OnScalableControlScaled(object sender, EventArgs e) + { + this.TryClearCache(); + } + + private void TryClearCache() + { + if (!this.SuppressCacheReseting) + { + this.cachedMeasures.Clear(); + } + } + + /// + /// Gets or sets whether to reset cache when scalable control is scaled + /// + internal bool SuppressCacheReseting { get; set; } + + // Finds and decrease size of all scalable elements in the given group box + private void DecreaseScalableElement() + { + foreach (object item in this.Items) + { + IScalableRibbonControl scalableRibbonControl = item as IScalableRibbonControl; + if (scalableRibbonControl == null) continue; + scalableRibbonControl.Reduce(); + } + } + + private void UpdateScalableControlSubscribing() + { + this.UpdateScalableControlSubscribing(true); + } + + private void UpdateScalableControlSubscribing(bool registerEvents) + { + foreach (var scalableRibbonControl in this.Items.OfType()) + { + // Always unregister first to ensure that we don't subscribe twice + scalableRibbonControl.Scaled -= this.OnScalableControlScaled; + + if (registerEvents) + { + scalableRibbonControl.Scaled += this.OnScalableControlScaled; + } + } + } + + #endregion + + #region Header + + /// + /// Gets or sets group box header + /// + public string Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = + DependencyProperty.Register("Header", typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata()); + + object IHeaderedControl.Header + { + get { return this.Header; } + + set { this.Header = (string)value; } + } + + #endregion + + #region IsLauncherVisible + + /// + /// Gets or sets dialog launcher button visibility + /// + public bool IsLauncherVisible + { + get { return (bool)this.GetValue(IsLauncherVisibleProperty); } + set { this.SetValue(IsLauncherVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsLauncherVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsLauncherVisibleProperty = + DependencyProperty.Register("IsLauncherVisible", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(false)); + + #endregion + + #region LauncherKeys + + /// + /// Gets or sets key tip for dialog launcher button + /// + [DisplayName("DialogLauncher Keys"), + Category("KeyTips"), + Description("Key tip keys for dialog launcher button")] + public string LauncherKeys + { + get { return (string)this.GetValue(DialogLauncherButtonKeyTipKeysProperty); } + set { this.SetValue(DialogLauncherButtonKeyTipKeysProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for + /// LauncherKeys. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DialogLauncherButtonKeyTipKeysProperty = + DependencyProperty.Register("LauncherKeys", + typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnDialogLauncherButtonKeyTipKeysChanged)); + + static void OnDialogLauncherButtonKeyTipKeysChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonGroupBox ribbonGroupBox = (RibbonGroupBox)d; + if (ribbonGroupBox.LauncherButton != null) + { + ribbonGroupBox.LauncherButton.KeyTip = (string)e.NewValue; + } + } + + #endregion + + #region LauncherIcon + + /// + /// Gets or sets launcher button icon + /// + public object LauncherIcon + { + get { return this.GetValue(LauncherIconProperty); } + set { this.SetValue(LauncherIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for LauncherIcon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LauncherIconProperty = + DependencyProperty.Register("LauncherIcon", typeof(object), typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged)); + + #endregion + + #region LauncherIcon + + /// + /// Gets or sets launcher button text + /// + public string LauncherText + { + get { return (string)this.GetValue(LauncherTextProperty); } + set { this.SetValue(LauncherTextProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for LauncherIcon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LauncherTextProperty = + DependencyProperty.Register("LauncherText", typeof(string), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); + + #endregion + + #region LauncherCommand + + /// + /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. + /// + [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] + public ICommand LauncherCommand + { + get + { + return (ICommand)this.GetValue(LauncherCommandProperty); + } + set + { + this.SetValue(LauncherCommandProperty, value); + } + } + + /// + /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. + /// + [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] + public object LauncherCommandParameter + { + get + { + return this.GetValue(LauncherCommandParameterProperty); + } + set + { + this.SetValue(LauncherCommandParameterProperty, value); + } + } + + /// + /// Gets or sets the element on which to raise the specified command. This is a dependency property. + /// + [Bindable(true), Category("Action")] + public IInputElement LauncherCommandTarget + { + get + { + return (IInputElement)this.GetValue(LauncherCommandTargetProperty); + } + set + { + this.SetValue(LauncherCommandTargetProperty, value); + } + } + + /// + /// Identifies the System.Windows.Controls.Primitives.ButtonBase.CommandParameter dependency property. + /// + public static readonly DependencyProperty LauncherCommandParameterProperty = DependencyProperty.Register("LauncherCommandParameter", typeof(object), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); + /// + /// Identifies the routed System.Windows.Controls.Primitives.ButtonBase.Command dependency property. + /// + public static readonly DependencyProperty LauncherCommandProperty = DependencyProperty.Register("LauncherCommand", typeof(ICommand), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); + + /// + /// Identifies the System.Windows.Controls.Primitives.ButtonBase.CommandTarget dependency property. + /// + public static readonly DependencyProperty LauncherCommandTargetProperty = DependencyProperty.Register("LauncherCommandTarget", typeof(IInputElement), typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null)); + + #endregion + + #region LauncherToolTip + + /// + /// Gets or sets launcher button tooltip + /// + public object LauncherToolTip + { + get { return (object)this.GetValue(LauncherToolTipProperty); } + set { this.SetValue(LauncherToolTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for LauncherToolTip. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LauncherToolTipProperty = + DependencyProperty.Register("LauncherToolTip", typeof(object), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); + + + + #endregion + + #region IsLauncherEnabled + + /// + /// Gets or sets whether launcher button is enabled + /// + public bool IsLauncherEnabled + { + get { return (bool)this.GetValue(IsLauncherEnabledProperty); } + set { this.SetValue(IsLauncherEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsLauncherEnabled. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsLauncherEnabledProperty = + DependencyProperty.Register("IsLauncherEnabled", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true)); + + #endregion + + #region LauncherButton + + /// + /// Gets launcher button + /// + public Button LauncherButton + { + get { return (Button)this.GetValue(LauncherButtonProperty); } + private set { this.SetValue(LauncherButtonPropertyKey, value); } + } + + private static readonly DependencyPropertyKey LauncherButtonPropertyKey = + DependencyProperty.RegisterReadOnly("LauncherButton", typeof(Button), typeof(RibbonGroupBox), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for LauncherButton. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LauncherButtonProperty = LauncherButtonPropertyKey.DependencyProperty; + + #endregion + + #region IsOpen + + /// + /// Gets or sets drop down popup visibility + /// + public bool IsDropDownOpen + { + get { return (bool)this.GetValue(IsDropDownOpenProperty); } + set { this.SetValue(IsDropDownOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(false, OnIsOpenChanged, CoerceIsDropDownOpen)); + + private static object CoerceIsDropDownOpen(DependencyObject d, object basevalue) + { + RibbonGroupBox box = d as RibbonGroupBox; + if ((box.State != RibbonGroupBoxState.Collapsed) && (box.State != RibbonGroupBoxState.QuickAccess)) return false; + return basevalue; + } + + #endregion + + #region LogicalChildren + + /// + /// Gets an enumerator for the logical child objects of + /// the System.Windows.Controls.ItemsControl object. + /// + protected override IEnumerator LogicalChildren + { + get + { + foreach (var item in this.Items) + { + yield return item; + } + + if (this.LauncherButton != null) + { + yield return this.LauncherButton; + } + } + } + + #endregion + + #region Icon + + /// + /// Gets or sets icon + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged)); + + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonGroupBox element = d as RibbonGroupBox; + FrameworkElement oldElement = e.OldValue as FrameworkElement; + if (oldElement != null) element.RemoveLogicalChild(oldElement); + FrameworkElement newElement = e.NewValue as FrameworkElement; + if (newElement != null) element.AddLogicalChild(newElement); + } + + #endregion + + #endregion + + #region Events + + /// + /// Dialog launcher btton click event + /// + public event RoutedEventHandler LauncherClick; + + /// + /// Occurs when context menu is opened + /// + public event EventHandler DropDownOpened; + + /// + /// Occurs when context menu is closed + /// + public event EventHandler DropDownClosed; + + #endregion + + #region Initialize + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonGroupBox() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(typeof(RibbonGroupBox))); + VisibilityProperty.AddOwner(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(OnVisibilityChanged)); + + PopupService.Attach(typeof(RibbonGroupBox)); + StyleProperty.OverrideMetadata(typeof(RibbonGroupBox), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + + ContextMenuService.Attach(typeof(RibbonGroupBox)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonGroupBox)); + } + + return basevalue; + } + + // Handles visibility changed + private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var box = (d as RibbonGroupBox); + if (box != null) box.ClearCache(); + } + + /// + /// Default constructor + /// + public RibbonGroupBox() + { + this.ToolTip = new ToolTip(); + ((ToolTip)this.ToolTip).Template = null; + this.CoerceValue(ContextMenuProperty); + this.Focusable = false; + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + + this.updateChildSizesItemContainerGeneratorAction = new ItemContainerGeneratorAction(this.ItemContainerGenerator, this.UpdateChildSizes); + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.SubscribeEvents(); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.UnSubscribeEvents(); + } + + private void SubscribeEvents() + { + // Always unsubscribe events to ensure we don't subscribe twice + this.UnSubscribeEvents(); + + this.UpdateScalableControlSubscribing(); + + if (this.LauncherButton != null) + { + this.LauncherButton.Click += this.OnDialogLauncherButtonClick; + } + + if (this.DropDownPopup != null) + { + this.DropDownPopup.Opened += this.OnPopupOpened; + this.DropDownPopup.Closed += this.OnPopupClosed; + } + } + + private void UnSubscribeEvents() + { + this.UpdateScalableControlSubscribing(false); + + if (this.LauncherButton != null) + { + this.LauncherButton.Click -= this.OnDialogLauncherButtonClick; + } + + if (this.DropDownPopup != null) + { + this.DropDownPopup.Opened -= this.OnPopupOpened; + this.DropDownPopup.Closed -= this.OnPopupClosed; + } + } + + #endregion + + #region Methods + + /// + /// Gets a panel with items + /// + /// + internal Panel GetPanel() { return this.upPanel; } + + /// + /// Gets cmmon layout root for popup and groupbox + /// + /// + internal Panel GetLayoutRoot() { return this.parentPanel; } + + #endregion + + #region Snapping + + /// + /// Snaps / Unsnaps the Visual + /// (remove visuals and substitute with freezed image) + /// + public bool IsSnapped + { + get + { + return this.isSnapped; + } + set + { + if (value == this.isSnapped) + { + return; + } + + if (value) + { + if (this.IsVisible) + { + // Render the freezed image + var renderTargetBitmap = new RenderTargetBitmap((int)this.ActualWidth, (int)this.ActualHeight, 96, 96, PixelFormats.Pbgra32); + renderTargetBitmap.Render((Visual)VisualTreeHelper.GetChild(this, 0)); + this.snappedImage.FlowDirection = this.FlowDirection; + this.snappedImage.Source = renderTargetBitmap; + this.snappedImage.Width = this.ActualWidth; + this.snappedImage.Height = this.ActualHeight; + this.snappedImage.Visibility = Visibility.Visible; + this.isSnapped = true; + } + } + else if (this.snappedImage != null) + { + // Clean up + this.snappedImage.Visibility = Visibility.Collapsed; + this.isSnapped = false; + } + + this.InvalidateVisual(); + } + } + + #endregion + + #region Caching + + // Pair of chached states + struct StateScale + { + public RibbonGroupBoxState State; + public int Scale; + } + + // Cache + readonly Dictionary cachedMeasures = new Dictionary(); + + /// + /// Gets or sets intermediate state of the group box + /// + internal RibbonGroupBoxState StateIntermediate + { + get; + set; + } + + /// + /// Gets or sets intermediate scale of the group box + /// + internal int ScaleIntermediate + { + get; + set; + } + + /// + /// Gets intermediate desired size + /// + internal Size DesiredSizeIntermediate + { + get + { + Size result; + var stateScale = this.GetCurrentIntermediateStateScale(); + + if (this.cachedMeasures.TryGetValue(stateScale, out result) == false) + { + this.SuppressCacheReseting = true; + this.UpdateScalableControlSubscribing(); + + // Get desired size for these values + var backupState = this.State; + var backupScale = this.Scale; + this.State = this.StateIntermediate; + this.Scale = this.ScaleIntermediate; + this.InvalidateLayout(); + this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + this.cachedMeasures.Add(stateScale, this.DesiredSize); + result = this.DesiredSize; + + // Rollback changes + this.State = backupState; + this.Scale = backupScale; + this.InvalidateLayout(); + this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + this.SuppressCacheReseting = false; + } + + return result; + } + } + + /// + /// Clears cache + /// + public void ClearCache() + { + this.cachedMeasures.Clear(); + } + + /// + /// Invalidates layout (with children) + /// + internal void InvalidateLayout() + { + InvalidateMeasureRecursive(this); + } + + private static void InvalidateMeasureRecursive(UIElement element) + { + if (element == null) + { + return; + } + + element.InvalidateMeasure(); + + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + var child = VisualTreeHelper.GetChild(element, i) as UIElement; + + if (child == null) + { + continue; + } + + InvalidateMeasureRecursive(child); + } + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code + /// or internal processes call System.Windows.FrameworkElement.ApplyTemplate(). + /// + public override void OnApplyTemplate() + { + this.UnSubscribeEvents(); + + // Clear cache + this.cachedMeasures.Clear(); + + this.LauncherButton = this.GetTemplateChild("PART_DialogLauncherButton") as Button; + + if (this.LauncherButton != null) + { + if (this.LauncherKeys != null) + { + this.LauncherButton.KeyTip = this.LauncherKeys; + } + } + + this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup; + + this.upPanel = this.GetTemplateChild("PART_UpPanel") as Panel; + this.parentPanel = this.GetTemplateChild("PART_ParentPanel") as Panel; + + this.snappedImage = this.GetTemplateChild("PART_SnappedImage") as Image; + + this.SubscribeEvents(); + } + + private void OnPopupOpened(object sender, EventArgs e) + { + if (this.DropDownOpened != null) this.DropDownOpened(this, e); + } + + private void OnPopupClosed(object sender, EventArgs e) + { + if (this.DropDownClosed != null) this.DropDownClosed(this, e); + } + + /// + /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDown + /// event reaches an element in its route that is derived from this class. + /// Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + if (e.Source != this + || this.DropDownPopup == null) + { + return; + } + + if (this.State == RibbonGroupBoxState.Collapsed + || this.State == RibbonGroupBoxState.QuickAccess) + { + e.Handled = true; + + if (!this.IsDropDownOpen) + { + this.IsDropDownOpen = true; + } + else + { + PopupService.RaiseDismissPopupEventAsync(this, DismissPopupMode.MouseNotOver); + } + } + } + + /// + /// Supports layout behavior when a child element is resized. + /// + /// The child element that is being resized. + protected override void OnChildDesiredSizeChanged(UIElement child) + { + base.OnChildDesiredSizeChanged(child); + + this.cachedMeasures.Remove(this.GetCurrentIntermediateStateScale()); + } + + private StateScale GetCurrentIntermediateStateScale() + { + var stateScale = new StateScale + { + Scale = this.ScaleIntermediate, + State = this.StateIntermediate + }; + return stateScale; + } + + #endregion + + #region Event Handling + + /// + /// Dialog launcher button click handler + /// + /// Sender + /// the event data + private void OnDialogLauncherButtonClick(object sender, RoutedEventArgs e) + { + if (this.LauncherClick != null) + { + this.LauncherClick(this, e); + } + } + + // Handles popup closing + private void OnRibbonGroupBoxPopupClosing() + { + //IsHitTestVisible = true; + if (Mouse.Captured == this) + { + Mouse.Capture(null); + } + } + + // handles popup opening + private void OnRibbonGroupBoxPopupOpening() + { + //IsHitTestVisible = false; + Mouse.Capture(this, CaptureMode.SubTree); + } + + /// + /// Handles IsOpen propertyu changes + /// + /// Object + /// The event data + private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (RibbonGroupBox)d; + + if (ribbon.IsDropDownOpen) + { + ribbon.OnRibbonGroupBoxPopupOpening(); + } + else + { + ribbon.OnRibbonGroupBoxPopupClosing(); + } + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public FrameworkElement CreateQuickAccessItem() + { + var groupBox = new RibbonGroupBox(); + + RibbonControl.BindQuickAccessItem(this, groupBox); + + groupBox.DropDownOpened += this.OnQuickAccessOpened; + groupBox.DropDownClosed += this.OnQuickAccessClosed; + + groupBox.State = RibbonGroupBoxState.QuickAccess; + + RibbonControl.Bind(this, groupBox, "ItemTemplateSelector", ItemTemplateSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "ItemsSource", ItemsSourceProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherCommandParameter", LauncherCommandParameterProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherCommand", LauncherCommandProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherCommandTarget", LauncherCommandTargetProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherIcon", LauncherIconProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherText", LauncherTextProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "LauncherToolTip", LauncherToolTipProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "IsLauncherEnabled", IsLauncherEnabledProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "IsLauncherVisible", IsLauncherVisibleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, groupBox, "DialogLauncherButtonKeyTipKeys", DialogLauncherButtonKeyTipKeysProperty, BindingMode.OneWay); + groupBox.LauncherClick += this.LauncherClick; + + var toolTip = this.ToolTip as ToolTip; + if ((toolTip == null || toolTip.ToolTip == null) && this.Header != null) + { + RibbonControl.Bind(this, groupBox, "Header", ToolTipProperty, BindingMode.OneWay); + } + + if (this.Icon != null) + { + var iconVisual = this.Icon as Visual; + if (iconVisual != null) + { + var rect = new Rectangle + { + Width = 16, + Height = 16, + Fill = new VisualBrush(iconVisual) + }; + groupBox.Icon = rect; + } + else + { + RibbonControl.Bind(this, groupBox, "Icon", RibbonControl.IconProperty, BindingMode.OneWay); + } + } + + if (this.Header != null) + { + RibbonControl.Bind(this, groupBox, "Header", RibbonControl.HeaderProperty, BindingMode.OneWay); + } + + return groupBox; + } + + private void OnQuickAccessOpened(object sender, EventArgs e) + { + if (!this.IsDropDownOpen + && !this.IsSnapped) + { + var groupBox = sender as RibbonGroupBox; + // Save state + this.IsSnapped = true; + + if (this.ItemsSource == null) + { + for (var i = 0; i < this.Items.Count; i++) + { + var item = this.Items[0]; + this.Items.Remove(item); + groupBox.Items.Add(item); + i--; + } + } + } + } + + private void OnQuickAccessClosed(object sender, EventArgs e) + { + var groupBox = sender as RibbonGroupBox; + + if (this.ItemsSource == null) + { + for (var i = 0; i < groupBox.Items.Count; i++) + { + var item = groupBox.Items[0]; + groupBox.Items.Remove(item); + this.Items.Add(item); + i--; + } + } + + this.IsSnapped = false; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = + DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IKeyTipedControl + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + if (this.State == RibbonGroupBoxState.Collapsed + || this.State == RibbonGroupBoxState.QuickAccess) + { + this.IsDropDownOpen = true; + } + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + this.IsDropDownOpen = false; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonGroupsContainer.cs b/Fluent.Ribbon/Controls/RibbonGroupsContainer.cs similarity index 95% rename from Fluent/Controls/RibbonGroupsContainer.cs rename to Fluent.Ribbon/Controls/RibbonGroupsContainer.cs index cb4c32ca3..ee578e6c4 100644 --- a/Fluent/Controls/RibbonGroupsContainer.cs +++ b/Fluent.Ribbon/Controls/RibbonGroupsContainer.cs @@ -1,610 +1,599 @@ -#region Copyright and License Information - -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license - -#endregion - -using System; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Media; - -namespace Fluent -{ - using Fluent.Internal; - - /// - /// Represent panel with ribbon group. - /// It is automatically adjusting size of controls - /// - public class RibbonGroupsContainer : Panel, IScrollInfo - { - #region Reduce Order - - /// - /// Gets or sets reduce order of group in the ribbon panel. - /// It must be enumerated with comma from the first to reduce to - /// the last to reduce (use Control.Name as group name in the enum). - /// Enclose in parentheses as (Control.Name) to reduce/enlarge - /// scalable elements in the given group - /// - public string ReduceOrder - { - get { return (string)this.GetValue(ReduceOrderProperty); } - set { this.SetValue(ReduceOrderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ReduceOrder. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ReduceOrderProperty = - DependencyProperty.Register("ReduceOrder", typeof(string), typeof(RibbonGroupsContainer), new UIPropertyMetadata(ReduceOrderPropertyChanged)); - - // handles ReduseOrder property changed - static void ReduceOrderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonGroupsContainer ribbonPanel = (RibbonGroupsContainer)d; - ribbonPanel.reduceOrder = ((string)e.NewValue).Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - ribbonPanel.reduceOrderIndex = ribbonPanel.reduceOrder.Length - 1; - - ribbonPanel.InvalidateMeasure(); - ribbonPanel.InvalidateArrange(); - } - - #endregion - - #region Fields - - private string[] reduceOrder = new string[0]; - private int reduceOrderIndex; - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonGroupsContainer() - : base() - { - this.Focusable = false; - } - - #endregion - - #region Layout Overridings - - /// - /// Returns a collection of the panel's UIElements. - /// - /// The logical parent of the collection to be created. - /// Returns an ordered collection of elements that have the specified logical parent. - protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) - { - return new UIElementCollection(this, /*Parent as FrameworkElement*/this); - } - - /// - /// Measures all of the RibbonGroupBox, and resize them appropriately - /// to fit within the available room - /// - /// The available size that this element can give to child elements. - /// The size that the groups container determines it needs during - /// layout, based on its calculations of child element sizes. - /// - protected override Size MeasureOverride(Size availableSize) - { - var desiredSize = this.GetChildrenDesiredSizeIntermediate(); - - if (this.reduceOrder.Length == 0) - { - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - // If we have more available space - try to expand groups - while (desiredSize.Width <= availableSize.Width) - { - var hasMoreVariants = this.reduceOrderIndex < this.reduceOrder.Length - 1; - if (!hasMoreVariants) - { - break; - } - - // Increase size of another item - this.reduceOrderIndex++; - this.IncreaseGroupBoxSize(this.reduceOrder[this.reduceOrderIndex]); - - desiredSize = this.GetChildrenDesiredSizeIntermediate(); - } - - // If not enough space - go to next variant - while (desiredSize.Width > availableSize.Width) - { - var hasMoreVariants = this.reduceOrderIndex >= 0; - if (!hasMoreVariants) - { - break; - } - - // Decrease size of another item - this.DecreaseGroupBoxSize(this.reduceOrder[this.reduceOrderIndex]); - this.reduceOrderIndex--; - - desiredSize = this.GetChildrenDesiredSizeIntermediate(); - } - - // Set find values - foreach (var item in this.InternalChildren) - { - var groupBox = item as RibbonGroupBox; - if (groupBox == null) - { - continue; - } - - if ((groupBox.State != groupBox.StateIntermediate) || - (groupBox.Scale != groupBox.ScaleIntermediate)) - { - groupBox.SuppressCacheReseting = true; - groupBox.State = groupBox.StateIntermediate; - groupBox.Scale = groupBox.ScaleIntermediate; - groupBox.InvalidateLayout(); - groupBox.Measure(new Size(double.PositiveInfinity, availableSize.Height)); - groupBox.SuppressCacheReseting = false; - } - - // Something wrong with cache? - if (groupBox.DesiredSizeIntermediate != groupBox.DesiredSize) - { - // Reset cache and reinvoke masure - groupBox.ClearCache(); - return this.MeasureOverride(availableSize); - } - } - - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - private Size GetChildrenDesiredSizeIntermediate() - { - double width = 0; - double height = 0; - - foreach (UIElement child in this.InternalChildren) - { - var groupBox = child as RibbonGroupBox; - if (groupBox == null) - { - continue; - } - - var desiredSize = groupBox.DesiredSizeIntermediate; - width += desiredSize.Width; - height = Math.Max(height, desiredSize.Height); - } - - return new Size(width, height); - } - - // Increase size of the item - private void IncreaseGroupBoxSize(string name) - { - var groupBox = this.FindGroup(name); - var scale = name.StartsWith("(", StringComparison.OrdinalIgnoreCase); - if (groupBox == null) - { - return; - } - - if (scale) - { - groupBox.ScaleIntermediate++; - } - else - { - groupBox.StateIntermediate = groupBox.StateIntermediate != RibbonGroupBoxState.Large - ? groupBox.StateIntermediate - 1 - : RibbonGroupBoxState.Large; - } - } - - // Decrease size of the item - private void DecreaseGroupBoxSize(string name) - { - var groupBox = this.FindGroup(name); - var scale = name.StartsWith("(", StringComparison.OrdinalIgnoreCase); - if (groupBox == null) - { - return; - } - - if (scale) - { - groupBox.ScaleIntermediate--; - } - else - { - groupBox.StateIntermediate = groupBox.StateIntermediate != RibbonGroupBoxState.Collapsed - ? groupBox.StateIntermediate + 1 - : groupBox.StateIntermediate; - } - } - - private RibbonGroupBox FindGroup(string name) - { - if (name.StartsWith("(", StringComparison.OrdinalIgnoreCase)) - { - name = name.Substring(1, name.Length - 2); - } - - foreach (FrameworkElement child in this.InternalChildren) - { - if (child.Name == name) - { - return child as RibbonGroupBox; - } - } - return null; - } - - /// - /// When overridden in a derived class, positions child elements and determines - /// a size for a System.Windows.FrameworkElement derived class. - /// - /// The final area within the parent that this element should use to arrange itself and its children. - /// The actual size used. - protected override Size ArrangeOverride(Size finalSize) - { - var finalRect = new Rect(finalSize) - { - X = -this.HorizontalOffset - }; - foreach (UIElement item in this.InternalChildren) - { - finalRect.Width = item.DesiredSize.Width; - finalRect.Height = Math.Max(finalSize.Height, item.DesiredSize.Height); - item.Arrange(finalRect); - finalRect.X += item.DesiredSize.Width; - } - return finalSize; - } - - #endregion - - #region IScrollInfo Members - - /// - /// Gets or sets a System.Windows.Controls.ScrollViewer element that controls scrolling behavior. - /// - public ScrollViewer ScrollOwner - { - get { return this.ScrollData.ScrollOwner; } - set { this.ScrollData.ScrollOwner = value; } - } - - /// - /// Sets the amount of horizontal offset. - /// - /// The degree to which content is horizontally offset from the containing viewport. - public void SetHorizontalOffset(double offset) - { - var newValue = CoerceOffset(ValidateInputOffset(offset, "HorizontalOffset"), this.scrollData.ExtentWidth, this.scrollData.ViewportWidth); - if (DoubleUtil.AreClose(this.ScrollData.OffsetX, newValue) == false) - { - this.scrollData.OffsetX = newValue; - this.InvalidateArrange(); - } - } - /// - /// Gets the horizontal size of the extent. - /// - public double ExtentWidth - { - get { return this.ScrollData.ExtentWidth; } - } - - /// - /// Gets the horizontal offset of the scrolled content. - /// - public double HorizontalOffset - { - get { return this.ScrollData.OffsetX; } - } - - /// - /// Gets the horizontal size of the viewport for this content. - /// - public double ViewportWidth - { - get { return this.ScrollData.ViewportWidth; } - } - - /// - /// Scrolls left within content by one logical unit. - /// - public void LineLeft() - { - this.SetHorizontalOffset(this.HorizontalOffset - 16.0); - } - - /// - /// Scrolls right within content by one logical unit. - /// - public void LineRight() - { - this.SetHorizontalOffset(this.HorizontalOffset + 16.0); - } - - /// - /// Forces content to scroll until the coordinate space of a System.Windows.Media.Visual object is visible. - /// This is optimized for horizontal scrolling only - /// - /// A System.Windows.Media.Visual that becomes visible. - /// A bounding rectangle that identifies the coordinate space to make visible. - /// A System.Windows.Rect that is visible. - public Rect MakeVisible(Visual visual, Rect rectangle) - { - // We can only work on visuals that are us or children. - // An empty rect has no size or position. We can't meaningfully use it. - if (rectangle.IsEmpty - || visual == null - || ReferenceEquals(visual, this) - || !this.IsAncestorOf(visual)) - { - return Rect.Empty; - } - - // Compute the child's rect relative to (0,0) in our coordinate space. - GeneralTransform childTransform = visual.TransformToAncestor(this); - - rectangle = childTransform.TransformBounds(rectangle); - - // Initialize the viewport - Rect viewport = new Rect(this.HorizontalOffset, rectangle.Top, this.ViewportWidth, rectangle.Height); - rectangle.X += viewport.X; - - // Compute the offsets required to minimally scroll the child maximally into view. - double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right); - - // We have computed the scrolling offsets; scroll to them. - this.SetHorizontalOffset(minX); - - // Compute the visible rectangle of the child relative to the viewport. - viewport.X = minX; - rectangle.Intersect(viewport); - - rectangle.X -= viewport.X; - - // Return the rectangle - return rectangle; - } - - static double ComputeScrollOffsetWithMinimalScroll( - double topView, - double bottomView, - double topChild, - double bottomChild) - { - // # CHILD POSITION CHILD SIZE SCROLL REMEDY - // 1 Above viewport <= viewport Down Align top edge of child & viewport - // 2 Above viewport > viewport Down Align bottom edge of child & viewport - // 3 Below viewport <= viewport Up Align bottom edge of child & viewport - // 4 Below viewport > viewport Up Align top edge of child & viewport - // 5 Entirely within viewport NA No scroll. - // 6 Spanning viewport NA No scroll. - // - // Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom - // "Below viewport" = childTop below viewportTop, childBottom below viewportBottom - // These child thus may overlap with the viewport, but will scroll the same direction - /*bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView); - bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);*/ - bool fAbove = (topChild < topView) && (bottomChild < bottomView); - bool fBelow = (bottomChild > bottomView) && (topChild > topView); - bool fLarger = (bottomChild - topChild) > (bottomView - topView); - - // Handle Cases: 1 & 4 above - if ((fAbove && !fLarger) - || (fBelow && fLarger)) - { - return topChild; - } - - // Handle Cases: 2 & 3 above - if (fAbove || fBelow) - { - return bottomChild - (bottomView - topView); - } - - // Handle cases: 5 & 6 above. - return topView; - } - - /// - /// Not implemented - /// - public void MouseWheelDown() - { - } - /// - /// Not implemented - /// - public void MouseWheelLeft() - { - } - /// - /// Not implemented - /// - public void MouseWheelRight() - { - } - /// - /// Not implemented - /// - public void MouseWheelUp() - { - } - /// - /// Not implemented - /// - public void LineDown() - { - } - /// - /// Not implemented - /// - public void LineUp() - { - } - /// - /// Not implemented - /// - public void PageDown() - { - } - /// - /// Not implemented - /// - public void PageLeft() - { - } - /// - /// Not implemented - /// - public void PageRight() - { - } - /// - /// Not implemented - /// - public void PageUp() - { - } - /// - /// Not implemented - /// - /// - public void SetVerticalOffset(double offset) - { - } - /// - /// Gets or sets a value that indicates whether scrolling on the vertical axis is possible. - /// - public bool CanVerticallyScroll - { - get { return false; } - set { } - } - /// - /// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible. - /// - public bool CanHorizontallyScroll - { - get { return true; } - set { } - } - /// - /// Not implemented - /// - public double ExtentHeight - { - get { return 0.0; } - }/// - /// Not implemented - /// - - public double VerticalOffset - { - get { return 0.0; } - } - /// - /// Not implemented - /// - public double ViewportHeight - { - get { return 0.0; } - } - - // Gets scroll data info - private ScrollData ScrollData - { - get - { - return this.scrollData ?? (this.scrollData = new ScrollData()); - } - } - - // Scroll data info - private ScrollData scrollData; - - // Validates input offset - static double ValidateInputOffset(double offset, string parameterName) - { - if (double.IsNaN(offset)) - { - throw new ArgumentOutOfRangeException(parameterName); - } - - return Math.Max(0.0, offset); - } - - // Verifies scrolling data using the passed viewport and extent as newly computed values. - // Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize] - // If extent, viewport, or the newly coerced offsets are different than the existing offset, - // cachces are updated and InvalidateScrollInfo() is called. - private void VerifyScrollData(double viewportWidth, double extentWidth) - { - bool isValid = true; - - if (double.IsInfinity(viewportWidth)) - { - viewportWidth = extentWidth; - } - - double offsetX = CoerceOffset(this.ScrollData.OffsetX, extentWidth, viewportWidth); - - isValid &= DoubleUtil.AreClose(viewportWidth, this.ScrollData.ViewportWidth); - isValid &= DoubleUtil.AreClose(extentWidth, this.ScrollData.ExtentWidth); - isValid &= DoubleUtil.AreClose(this.ScrollData.OffsetX, offsetX); - - this.ScrollData.ViewportWidth = viewportWidth; - this.ScrollData.ExtentWidth = extentWidth; - this.ScrollData.OffsetX = offsetX; - - if (!isValid) - { - if (this.ScrollOwner != null) - { - this.ScrollOwner.InvalidateScrollInfo(); - } - } - } - - // Returns an offset coerced into the [0, Extent - Viewport] range. - static double CoerceOffset(double offset, double extent, double viewport) - { - if (offset > extent - viewport) - { - offset = extent - viewport; - } - - if (offset < 0) - { - offset = 0; - } - - return offset; - } - - #endregion - } -} +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; + +namespace Fluent +{ + using Fluent.Internal; + + /// + /// Represent panel with ribbon group. + /// It is automatically adjusting size of controls + /// + public class RibbonGroupsContainer : Panel, IScrollInfo + { + #region Reduce Order + + /// + /// Gets or sets reduce order of group in the ribbon panel. + /// It must be enumerated with comma from the first to reduce to + /// the last to reduce (use Control.Name as group name in the enum). + /// Enclose in parentheses as (Control.Name) to reduce/enlarge + /// scalable elements in the given group + /// + public string ReduceOrder + { + get { return (string)this.GetValue(ReduceOrderProperty); } + set { this.SetValue(ReduceOrderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ReduceOrder. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ReduceOrderProperty = + DependencyProperty.Register("ReduceOrder", typeof(string), typeof(RibbonGroupsContainer), new UIPropertyMetadata(ReduceOrderPropertyChanged)); + + // handles ReduseOrder property changed + static void ReduceOrderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonGroupsContainer ribbonPanel = (RibbonGroupsContainer)d; + ribbonPanel.reduceOrder = ((string)e.NewValue).Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + ribbonPanel.reduceOrderIndex = ribbonPanel.reduceOrder.Length - 1; + + ribbonPanel.InvalidateMeasure(); + ribbonPanel.InvalidateArrange(); + } + + #endregion + + #region Fields + + private string[] reduceOrder = new string[0]; + private int reduceOrderIndex; + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public RibbonGroupsContainer() + : base() + { + this.Focusable = false; + } + + #endregion + + #region Layout Overridings + + /// + /// Returns a collection of the panel's UIElements. + /// + /// The logical parent of the collection to be created. + /// Returns an ordered collection of elements that have the specified logical parent. + protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent) + { + return new UIElementCollection(this, /*Parent as FrameworkElement*/this); + } + + /// + /// Measures all of the RibbonGroupBox, and resize them appropriately + /// to fit within the available room + /// + /// The available size that this element can give to child elements. + /// The size that the groups container determines it needs during + /// layout, based on its calculations of child element sizes. + /// + protected override Size MeasureOverride(Size availableSize) + { + var desiredSize = this.GetChildrenDesiredSizeIntermediate(); + + if (this.reduceOrder.Length == 0) + { + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + // If we have more available space - try to expand groups + while (desiredSize.Width <= availableSize.Width) + { + var hasMoreVariants = this.reduceOrderIndex < this.reduceOrder.Length - 1; + if (!hasMoreVariants) + { + break; + } + + // Increase size of another item + this.reduceOrderIndex++; + this.IncreaseGroupBoxSize(this.reduceOrder[this.reduceOrderIndex]); + + desiredSize = this.GetChildrenDesiredSizeIntermediate(); + } + + // If not enough space - go to next variant + while (desiredSize.Width > availableSize.Width) + { + var hasMoreVariants = this.reduceOrderIndex >= 0; + if (!hasMoreVariants) + { + break; + } + + // Decrease size of another item + this.DecreaseGroupBoxSize(this.reduceOrder[this.reduceOrderIndex]); + this.reduceOrderIndex--; + + desiredSize = this.GetChildrenDesiredSizeIntermediate(); + } + + // Set find values + foreach (var item in this.InternalChildren) + { + var groupBox = item as RibbonGroupBox; + if (groupBox == null) + { + continue; + } + + if ((groupBox.State != groupBox.StateIntermediate) || + (groupBox.Scale != groupBox.ScaleIntermediate)) + { + groupBox.SuppressCacheReseting = true; + groupBox.State = groupBox.StateIntermediate; + groupBox.Scale = groupBox.ScaleIntermediate; + groupBox.InvalidateLayout(); + groupBox.Measure(new Size(double.PositiveInfinity, availableSize.Height)); + groupBox.SuppressCacheReseting = false; + } + + // Something wrong with cache? + if (groupBox.DesiredSizeIntermediate != groupBox.DesiredSize) + { + // Reset cache and reinvoke masure + groupBox.ClearCache(); + return this.MeasureOverride(availableSize); + } + } + + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + private Size GetChildrenDesiredSizeIntermediate() + { + double width = 0; + double height = 0; + + foreach (UIElement child in this.InternalChildren) + { + var groupBox = child as RibbonGroupBox; + if (groupBox == null) + { + continue; + } + + var desiredSize = groupBox.DesiredSizeIntermediate; + width += desiredSize.Width; + height = Math.Max(height, desiredSize.Height); + } + + return new Size(width, height); + } + + // Increase size of the item + private void IncreaseGroupBoxSize(string name) + { + var groupBox = this.FindGroup(name); + var scale = name.StartsWith("(", StringComparison.OrdinalIgnoreCase); + if (groupBox == null) + { + return; + } + + if (scale) + { + groupBox.ScaleIntermediate++; + } + else + { + groupBox.StateIntermediate = groupBox.StateIntermediate != RibbonGroupBoxState.Large + ? groupBox.StateIntermediate - 1 + : RibbonGroupBoxState.Large; + } + } + + // Decrease size of the item + private void DecreaseGroupBoxSize(string name) + { + var groupBox = this.FindGroup(name); + var scale = name.StartsWith("(", StringComparison.OrdinalIgnoreCase); + if (groupBox == null) + { + return; + } + + if (scale) + { + groupBox.ScaleIntermediate--; + } + else + { + groupBox.StateIntermediate = groupBox.StateIntermediate != RibbonGroupBoxState.Collapsed + ? groupBox.StateIntermediate + 1 + : groupBox.StateIntermediate; + } + } + + private RibbonGroupBox FindGroup(string name) + { + if (name.StartsWith("(", StringComparison.OrdinalIgnoreCase)) + { + name = name.Substring(1, name.Length - 2); + } + + foreach (FrameworkElement child in this.InternalChildren) + { + if (child.Name == name) + { + return child as RibbonGroupBox; + } + } + return null; + } + + /// + /// When overridden in a derived class, positions child elements and determines + /// a size for a System.Windows.FrameworkElement derived class. + /// + /// The final area within the parent that this element should use to arrange itself and its children. + /// The actual size used. + protected override Size ArrangeOverride(Size finalSize) + { + var finalRect = new Rect(finalSize) + { + X = -this.HorizontalOffset + }; + foreach (UIElement item in this.InternalChildren) + { + finalRect.Width = item.DesiredSize.Width; + finalRect.Height = Math.Max(finalSize.Height, item.DesiredSize.Height); + item.Arrange(finalRect); + finalRect.X += item.DesiredSize.Width; + } + return finalSize; + } + + #endregion + + #region IScrollInfo Members + + /// + /// Gets or sets a System.Windows.Controls.ScrollViewer element that controls scrolling behavior. + /// + public ScrollViewer ScrollOwner + { + get { return this.ScrollData.ScrollOwner; } + set { this.ScrollData.ScrollOwner = value; } + } + + /// + /// Sets the amount of horizontal offset. + /// + /// The degree to which content is horizontally offset from the containing viewport. + public void SetHorizontalOffset(double offset) + { + var newValue = CoerceOffset(ValidateInputOffset(offset, "HorizontalOffset"), this.scrollData.ExtentWidth, this.scrollData.ViewportWidth); + if (DoubleUtil.AreClose(this.ScrollData.OffsetX, newValue) == false) + { + this.scrollData.OffsetX = newValue; + this.InvalidateArrange(); + } + } + /// + /// Gets the horizontal size of the extent. + /// + public double ExtentWidth + { + get { return this.ScrollData.ExtentWidth; } + } + + /// + /// Gets the horizontal offset of the scrolled content. + /// + public double HorizontalOffset + { + get { return this.ScrollData.OffsetX; } + } + + /// + /// Gets the horizontal size of the viewport for this content. + /// + public double ViewportWidth + { + get { return this.ScrollData.ViewportWidth; } + } + + /// + /// Scrolls left within content by one logical unit. + /// + public void LineLeft() + { + this.SetHorizontalOffset(this.HorizontalOffset - 16.0); + } + + /// + /// Scrolls right within content by one logical unit. + /// + public void LineRight() + { + this.SetHorizontalOffset(this.HorizontalOffset + 16.0); + } + + /// + /// Forces content to scroll until the coordinate space of a System.Windows.Media.Visual object is visible. + /// This is optimized for horizontal scrolling only + /// + /// A System.Windows.Media.Visual that becomes visible. + /// A bounding rectangle that identifies the coordinate space to make visible. + /// A System.Windows.Rect that is visible. + public Rect MakeVisible(Visual visual, Rect rectangle) + { + // We can only work on visuals that are us or children. + // An empty rect has no size or position. We can't meaningfully use it. + if (rectangle.IsEmpty + || visual == null + || ReferenceEquals(visual, this) + || !this.IsAncestorOf(visual)) + { + return Rect.Empty; + } + + // Compute the child's rect relative to (0,0) in our coordinate space. + GeneralTransform childTransform = visual.TransformToAncestor(this); + + rectangle = childTransform.TransformBounds(rectangle); + + // Initialize the viewport + Rect viewport = new Rect(this.HorizontalOffset, rectangle.Top, this.ViewportWidth, rectangle.Height); + rectangle.X += viewport.X; + + // Compute the offsets required to minimally scroll the child maximally into view. + double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right); + + // We have computed the scrolling offsets; scroll to them. + this.SetHorizontalOffset(minX); + + // Compute the visible rectangle of the child relative to the viewport. + viewport.X = minX; + rectangle.Intersect(viewport); + + rectangle.X -= viewport.X; + + // Return the rectangle + return rectangle; + } + + static double ComputeScrollOffsetWithMinimalScroll( + double topView, + double bottomView, + double topChild, + double bottomChild) + { + // # CHILD POSITION CHILD SIZE SCROLL REMEDY + // 1 Above viewport <= viewport Down Align top edge of child & viewport + // 2 Above viewport > viewport Down Align bottom edge of child & viewport + // 3 Below viewport <= viewport Up Align bottom edge of child & viewport + // 4 Below viewport > viewport Up Align top edge of child & viewport + // 5 Entirely within viewport NA No scroll. + // 6 Spanning viewport NA No scroll. + // + // Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom + // "Below viewport" = childTop below viewportTop, childBottom below viewportBottom + // These child thus may overlap with the viewport, but will scroll the same direction + /*bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView); + bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);*/ + bool fAbove = (topChild < topView) && (bottomChild < bottomView); + bool fBelow = (bottomChild > bottomView) && (topChild > topView); + bool fLarger = (bottomChild - topChild) > (bottomView - topView); + + // Handle Cases: 1 & 4 above + if ((fAbove && !fLarger) + || (fBelow && fLarger)) + { + return topChild; + } + + // Handle Cases: 2 & 3 above + if (fAbove || fBelow) + { + return bottomChild - (bottomView - topView); + } + + // Handle cases: 5 & 6 above. + return topView; + } + + /// + /// Not implemented + /// + public void MouseWheelDown() + { + } + /// + /// Not implemented + /// + public void MouseWheelLeft() + { + } + /// + /// Not implemented + /// + public void MouseWheelRight() + { + } + /// + /// Not implemented + /// + public void MouseWheelUp() + { + } + /// + /// Not implemented + /// + public void LineDown() + { + } + /// + /// Not implemented + /// + public void LineUp() + { + } + /// + /// Not implemented + /// + public void PageDown() + { + } + /// + /// Not implemented + /// + public void PageLeft() + { + } + /// + /// Not implemented + /// + public void PageRight() + { + } + /// + /// Not implemented + /// + public void PageUp() + { + } + /// + /// Not implemented + /// + /// + public void SetVerticalOffset(double offset) + { + } + /// + /// Gets or sets a value that indicates whether scrolling on the vertical axis is possible. + /// + public bool CanVerticallyScroll + { + get { return false; } + set { } + } + /// + /// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible. + /// + public bool CanHorizontallyScroll + { + get { return true; } + set { } + } + /// + /// Not implemented + /// + public double ExtentHeight + { + get { return 0.0; } + }/// + /// Not implemented + /// + + public double VerticalOffset + { + get { return 0.0; } + } + /// + /// Not implemented + /// + public double ViewportHeight + { + get { return 0.0; } + } + + // Gets scroll data info + private ScrollData ScrollData + { + get + { + return this.scrollData ?? (this.scrollData = new ScrollData()); + } + } + + // Scroll data info + private ScrollData scrollData; + + // Validates input offset + static double ValidateInputOffset(double offset, string parameterName) + { + if (double.IsNaN(offset)) + { + throw new ArgumentOutOfRangeException(parameterName); + } + + return Math.Max(0.0, offset); + } + + // Verifies scrolling data using the passed viewport and extent as newly computed values. + // Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize] + // If extent, viewport, or the newly coerced offsets are different than the existing offset, + // cachces are updated and InvalidateScrollInfo() is called. + private void VerifyScrollData(double viewportWidth, double extentWidth) + { + bool isValid = true; + + if (double.IsInfinity(viewportWidth)) + { + viewportWidth = extentWidth; + } + + double offsetX = CoerceOffset(this.ScrollData.OffsetX, extentWidth, viewportWidth); + + isValid &= DoubleUtil.AreClose(viewportWidth, this.ScrollData.ViewportWidth); + isValid &= DoubleUtil.AreClose(extentWidth, this.ScrollData.ExtentWidth); + isValid &= DoubleUtil.AreClose(this.ScrollData.OffsetX, offsetX); + + this.ScrollData.ViewportWidth = viewportWidth; + this.ScrollData.ExtentWidth = extentWidth; + this.ScrollData.OffsetX = offsetX; + + if (!isValid) + { + if (this.ScrollOwner != null) + { + this.ScrollOwner.InvalidateScrollInfo(); + } + } + } + + // Returns an offset coerced into the [0, Extent - Viewport] range. + static double CoerceOffset(double offset, double extent, double viewport) + { + if (offset > extent - viewport) + { + offset = extent - viewport; + } + + if (offset < 0) + { + offset = 0; + } + + return offset; + } + + #endregion + } +} diff --git a/Fluent/Controls/RibbonItemsControl.cs b/Fluent.Ribbon/Controls/RibbonItemsControl.cs similarity index 89% rename from Fluent/Controls/RibbonItemsControl.cs rename to Fluent.Ribbon/Controls/RibbonItemsControl.cs index 850d8a6f9..40278a622 100644 --- a/Fluent/Controls/RibbonItemsControl.cs +++ b/Fluent.Ribbon/Controls/RibbonItemsControl.cs @@ -1,186 +1,176 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents ribbon items control - /// - [ContentProperty("Items")] - public abstract class RibbonItemsControl : ItemsControl, IQuickAccessItemProvider, IRibbonControl - { - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return (ImageSource)this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonItemsControl() - { - Type type = typeof(RibbonItemsControl); - ToolTipService.Attach(type); - ContextMenuService.Attach(type); - } - - /// - /// Default Constructor - /// - protected RibbonItemsControl() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region QuickAccess - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public abstract FrameworkElement CreateQuickAccessItem(); - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(RibbonItemsControl)); - - #endregion - - #region Methods - - /// - /// Handles key tip pressed - /// - public virtual void OnKeyTipPressed() - { - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents ribbon items control + /// + [ContentProperty("Items")] + public abstract class RibbonItemsControl : ItemsControl, IQuickAccessItemProvider, IRibbonControl + { + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonItemsControl() + { + Type type = typeof(RibbonItemsControl); + ToolTipService.Attach(type); + ContextMenuService.Attach(type); + } + + /// + /// Default Constructor + /// + protected RibbonItemsControl() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region QuickAccess + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public abstract FrameworkElement CreateQuickAccessItem(); + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(RibbonItemsControl)); + + #endregion + + #region Methods + + /// + /// Handles key tip pressed + /// + public virtual void OnKeyTipPressed() + { + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/RibbonMenu.cs b/Fluent.Ribbon/Controls/RibbonMenu.cs similarity index 97% rename from Fluent/Controls/RibbonMenu.cs rename to Fluent.Ribbon/Controls/RibbonMenu.cs index 0e3433827..16055b062 100644 --- a/Fluent/Controls/RibbonMenu.cs +++ b/Fluent.Ribbon/Controls/RibbonMenu.cs @@ -1,97 +1,97 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents menu in combo box and gallery - /// - [ContentProperty("Items")] - public class RibbonMenu : MenuBase - { - #region Constructors - - static RibbonMenu() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonMenu), new FrameworkPropertyMetadata(typeof(RibbonMenu))); - StyleProperty.OverrideMetadata(typeof(RibbonMenu), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonMenu)); - } - - return basevalue; - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new MenuItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is System.Windows.Controls.MenuItem - || item is Separator; - } - - /// - /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The that contains the event data. - protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) - { - //base.OnGotKeyboardFocus(e); - IInputElement element = this.GetRootDropDownControl() as IInputElement; - if (element != null) Keyboard.Focus(element); - } - - /*protected override void OnGotMouseCapture(MouseEventArgs e) - { - IInputElement element = GetRootDropDownControl() as IInputElement; - if ((element!=null)&&(Mouse.Captured!=element)) Mouse.Capture(element, CaptureMode.SubTree); - }*/ - - private IDropDownControl GetRootDropDownControl() - { - DependencyObject element = this; - while (element != null) - { - IDropDownControl popup = element as IDropDownControl; - if (popup != null) return popup; - DependencyObject elementParent = VisualTreeHelper.GetParent(element); - if (elementParent == null) element = LogicalTreeHelper.GetParent(element); - else element = elementParent; - } - return null; - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents menu in combo box and gallery + /// + [ContentProperty("Items")] + public class RibbonMenu : MenuBase + { + #region Constructors + + static RibbonMenu() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonMenu), new FrameworkPropertyMetadata(typeof(RibbonMenu))); + StyleProperty.OverrideMetadata(typeof(RibbonMenu), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonMenu)); + } + + return basevalue; + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new MenuItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is System.Windows.Controls.MenuItem + || item is Separator; + } + + /// + /// Invoked when an unhandled  attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. + protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e) + { + //base.OnGotKeyboardFocus(e); + IInputElement element = this.GetRootDropDownControl() as IInputElement; + if (element != null) Keyboard.Focus(element); + } + + /*protected override void OnGotMouseCapture(MouseEventArgs e) + { + IInputElement element = GetRootDropDownControl() as IInputElement; + if ((element!=null)&&(Mouse.Captured!=element)) Mouse.Capture(element, CaptureMode.SubTree); + }*/ + + private IDropDownControl GetRootDropDownControl() + { + DependencyObject element = this; + while (element != null) + { + IDropDownControl popup = element as IDropDownControl; + if (popup != null) return popup; + DependencyObject elementParent = VisualTreeHelper.GetParent(element); + if (elementParent == null) element = LogicalTreeHelper.GetParent(element); + else element = elementParent; + } + return null; + } + + #endregion + } +} diff --git a/Fluent/Controls/RibbonScrollViewer.cs b/Fluent.Ribbon/Controls/RibbonScrollViewer.cs similarity index 65% rename from Fluent/Controls/RibbonScrollViewer.cs rename to Fluent.Ribbon/Controls/RibbonScrollViewer.cs index e30bab327..466d5aa53 100644 --- a/Fluent/Controls/RibbonScrollViewer.cs +++ b/Fluent.Ribbon/Controls/RibbonScrollViewer.cs @@ -1,39 +1,27 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Windows.Controls; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents ScrollViewer with modified hit test - /// - public class RibbonScrollViewer : ScrollViewer - { - #region Overrides - - /// - /// Performs a hit test to determine whether the specified - /// points are within the bounds of this ScrollViewer - /// - /// The result of the hit test - /// The parameters for hit testing within a visual object - protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) - { - if (this.VisualChildrenCount > 0) - { - return VisualTreeHelper.HitTest(this.GetVisualChild(0), hitTestParameters.HitPoint); - } - return base.HitTestCore(hitTestParameters); - } - - #endregion - } -} +using System.Windows.Controls; +using System.Windows.Media; + +namespace Fluent +{ + /// + /// Represents ScrollViewer with modified hit test + /// + public class RibbonScrollViewer : ScrollViewer + { + /// + /// Performs a hit test to determine whether the specified + /// points are within the bounds of this ScrollViewer + /// + /// The result of the hit test + /// The parameters for hit testing within a visual object + protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) + { + if (this.VisualChildrenCount > 0) + { + return VisualTreeHelper.HitTest(this.GetVisualChild(0), hitTestParameters.HitPoint); + } + + return base.HitTestCore(hitTestParameters); + } + } +} \ No newline at end of file diff --git a/Fluent/Controls/RibbonTabControl.cs b/Fluent.Ribbon/Controls/RibbonTabControl.cs similarity index 95% rename from Fluent/Controls/RibbonTabControl.cs rename to Fluent.Ribbon/Controls/RibbonTabControl.cs index 08ec3cdc3..51a6f4226 100644 --- a/Fluent/Controls/RibbonTabControl.cs +++ b/Fluent.Ribbon/Controls/RibbonTabControl.cs @@ -1,830 +1,836 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Runtime.InteropServices; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Input; - using System.Windows.Media; - using Fluent.Metro.Native; - - /// - /// Represents ribbon tab control - /// - [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonTabItem))] - [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] - [TemplatePart(Name = "PART_TabsContainer", Type = typeof(IScrollInfo))] - [TemplatePart(Name = "PART_ToolbarPanel", Type = typeof(Panel))] - public class RibbonTabControl : Selector, IDropDownControl - { - #region Fields - - // Collection of toolbar items - private ObservableCollection toolBarItems; - - // ToolBar panel - private Panel toolbarPanel; - - #endregion - - #region Events - - /// - /// Event which is fired when the, maybe listening, should be closed - /// - public event EventHandler RequestBackstageClose; - - #endregion - - #region Properties - - #region Menu - - /// - /// Gets or sets file menu control (can be application menu button, backstage button and so on) - /// - public UIElement Menu - { - get { return (UIElement)this.GetValue(MenuProperty); } - set { this.SetValue(MenuProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Button. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MenuProperty = - DependencyProperty.Register("Menu", typeof(UIElement), - typeof(RibbonTabControl), new UIPropertyMetadata(null)); - - #endregion - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup { get; private set; } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - /// - /// Gets content of selected tab item - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public object SelectedContent - { - get - { - return this.GetValue(SelectedContentProperty); - } - internal set - { - this.SetValue(SelectedContentPropertyKey, value); - } - } - - // DependencyProperty key for SelectedContent - static readonly DependencyPropertyKey SelectedContentPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContent", typeof(object), typeof(RibbonTabControl), new FrameworkPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectedContentProperty = SelectedContentPropertyKey.DependencyProperty; - - /// - /// Gets or sets whether ribbon is minimized - /// - public bool IsMinimized - { - get { return (bool)this.GetValue(IsMinimizedProperty); } - set { this.SetValue(IsMinimizedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsMinimizedProperty = DependencyProperty.Register("IsMinimized", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(false, OnMinimizedChanged)); - - /// - /// Gets or sets whether ribbon popup is opened - /// - public bool IsDropDownOpen - { - get { return (bool)this.GetValue(IsDropDownOpenProperty); } - set { this.SetValue(IsDropDownOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(false, OnIsDropDownOpenChanged, CoerceIsDropDownOpen)); - - private static object CoerceIsDropDownOpen(DependencyObject d, object basevalue) - { - var tabControl = d as RibbonTabControl; - - if (tabControl == null) - { - return basevalue; - } - - if (!tabControl.IsMinimized) - { - return false; - } - - return basevalue; - } - - /// - /// Defines if the currently selected item should draw it's highlight/selected borders - /// - public bool HighlightSelectedItem - { - get { return (bool)this.GetValue(HighlightSelectedItemProperty); } - set { this.SetValue(HighlightSelectedItemProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HighlightSelectedItemProperty = - DependencyProperty.RegisterAttached("HighlightSelectedItem", typeof(bool), typeof(RibbonTabControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// Gets whether ribbon tabs can scroll - /// - internal bool CanScroll - { - get - { - var scrollInfo = this.GetTemplateChild("PART_TabsContainer") as IScrollInfo; - if (scrollInfo != null) - { - return scrollInfo.ExtentWidth > scrollInfo.ViewportWidth; - } - - return false; - } - } - - /// - /// Gets or sets selected tab item - /// - internal RibbonTabItem SelectedTabItem - { - get { return (RibbonTabItem)this.GetValue(SelectedTabItemProperty); } - private set { this.SetValue(SelectedTabItemProperty, value); } - } - - // Using a DependencyProperty as the backing store for SelectedTabItem. This enables animation, styling, binding, etc... - internal static readonly DependencyProperty SelectedTabItemProperty = - DependencyProperty.Register("SelectedTabItem", typeof(RibbonTabItem), typeof(RibbonTabControl), new UIPropertyMetadata(null)); - - /// - /// Gets collection of ribbon toolbar items - /// - public ObservableCollection ToolBarItems - { - get - { - if (this.toolBarItems == null) - { - this.toolBarItems = new ObservableCollection(); - this.toolBarItems.CollectionChanged += this.OnToolbarItemsCollectionChanged; - } - - return this.toolBarItems; - } - } - - internal Panel ToolbarPanel - { - get { return this.toolbarPanel; } - } - - // Handle toolbar iitems changes - private void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (this.ToolbarPanel == null) - { - return; - } - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (var i = 0; i < e.NewItems.Count; i++) - { - this.ToolbarPanel.Children.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (var obj3 in e.OldItems.OfType()) - { - this.ToolbarPanel.Children.Remove(obj3); - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var obj4 in e.OldItems.OfType()) - { - this.ToolbarPanel.Children.Remove(obj4); - } - foreach (var obj5 in e.NewItems.OfType()) - { - this.ToolbarPanel.Children.Add(obj5); - } - break; - - case NotifyCollectionChangedAction.Reset: - this.toolbarPanel.Children.Clear(); - foreach (var toolBarItem in this.ToolBarItems) - { - this.ToolbarPanel.Children.Add(toolBarItem); - } - break; - } - - } - - /// - /// Gets or sets the height of the gap between the ribbon and the content - /// - public double ContentGapHeight - { - get { return (double)this.GetValue(ContentGapHeightProperty); } - set { this.SetValue(ContentGapHeightProperty, value); } - } - - /// - /// DependencyProperty for - /// - public static readonly DependencyProperty ContentGapHeightProperty = - DependencyProperty.Register("ContentGapHeight", typeof(double), typeof(RibbonTabControl), new UIPropertyMetadata(5D)); - - #endregion - - #region Initializion - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonTabControl() - { - var type = typeof(RibbonTabControl); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(typeof(RibbonTabControl))); - ContextMenuService.Attach(type); - PopupService.Attach(type); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - // Coerce object style - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = ((FrameworkElement)d).TryFindResource(typeof(RibbonTabControl)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public RibbonTabControl() - { - ContextMenuService.Coerce(this); - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - #endregion - - #region Overrides - - /// - /// Raises the System.Windows.FrameworkElement.Initialized event. - /// This method is invoked whenever System.Windows. - /// FrameworkElement.IsInitialized is set to true internally. - /// - /// The System.Windows.RoutedEventArgs that contains the event data. - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - this.ItemContainerGenerator.StatusChanged += this.OnGeneratorStatusChanged; - } - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new RibbonTabItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// true if the item is (or is eligible to be) its own container; otherwise, false. - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is RibbonTabItem; - } - - /// - /// When overridden in a derived class, is invoked whenever application code or - /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). - /// - public override void OnApplyTemplate() - { - this.DropDownPopup = this.Template.FindName("PART_Popup", this) as Popup; - if (this.DropDownPopup != null) - { - this.DropDownPopup.CustomPopupPlacementCallback = this.CustomPopupPlacementMethod; - } - - if (this.ToolbarPanel != null - && this.toolBarItems != null) - { - for (var i = 0; i < this.toolBarItems.Count; i++) - { - this.ToolbarPanel.Children.Remove(this.toolBarItems[i]); - } - } - - this.toolbarPanel = this.Template.FindName("PART_ToolbarPanel", this) as Panel; - - if (this.ToolbarPanel != null - && this.toolBarItems != null) - { - for (var i = 0; i < this.toolBarItems.Count; i++) - { - this.ToolbarPanel.Children.Add(this.toolBarItems[i]); - } - } - } - - /// - /// Updates the current selection when an item in the System.Windows.Controls.Primitives.Selector has changed - /// - /// The event data. - protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) - { - base.OnItemsChanged(e); - - if (this.IsMinimized - && this.IsDropDownOpen == false) - { - return; - } - - if (e.Action == NotifyCollectionChangedAction.Remove - && this.SelectedIndex == -1) - { - var startIndex = e.OldStartingIndex + 1; - if (startIndex > this.Items.Count) - { - startIndex = 0; - } - - var item = this.FindNextTabItem(startIndex, -1); - if (item != null) - { - item.IsSelected = true; - } - else - { - this.SelectedContent = null; - } - } - } - - /// - /// Called when the selection changes. - /// - /// The event data. - protected override void OnSelectionChanged(SelectionChangedEventArgs e) - { - this.UpdateSelectedContent(); - - if (e.AddedItems.Count > 0) - { - if (this.IsMinimized) - { - this.IsDropDownOpen = true; - - ((RibbonTabItem)e.AddedItems[0]).IsHitTestVisible = false; - } - } - else - { - if (this.IsDropDownOpen) - { - this.IsDropDownOpen = false; - } - } - - if (e.RemovedItems.Count > 0) - { - ((RibbonTabItem)e.RemovedItems[0]).IsHitTestVisible = true; - } - - base.OnSelectionChanged(e); - } - - /// - /// Invoked when an unhandled System.Windows.Input.Mouse.PreviewMouseWheel  - /// attached event reaches an element in its route that is derived from this class. - /// Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseWheelEventArgs that contains the event data. - protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) - { - //base.OnPreviewMouseWheel(e); - this.ProcessMouseWheel(e); - } - - /// - /// Invoked when the event is received. - /// - /// Information about the event. - protected override void OnKeyDown(KeyEventArgs e) - { - this.OnKeyUp(e); - - if (e.Handled) - { - return; - } - - switch (e.Key) - { - case Key.Escape: - if (this.IsDropDownOpen) - { - this.IsDropDownOpen = false; - } - break; - } - } - - #endregion - - #region Private methods - - private static bool IsRibbonAncestorOf(DependencyObject element) - { - while (element != null) - { - if (element is Ribbon) - { - return true; - } - - var parent = LogicalTreeHelper.GetParent(element) ?? VisualTreeHelper.GetParent(element); - - element = parent; - } - - return false; - } - - // Process mouse wheel event - internal void ProcessMouseWheel(MouseWheelEventArgs e) - { - if (this.IsMinimized - || this.SelectedItem == null) - { - return; - } - - var focusedElement = Keyboard.FocusedElement as DependencyObject; - - if (focusedElement != null - && IsRibbonAncestorOf(focusedElement)) - { - return; - } - - var visualItems = new List(); - var selectedIndex = -1; - -#if NET45 - var tabs = this.ItemContainerGenerator.Items.OfType() - .Where(x => x.Visibility == Visibility.Visible && (x.IsContextual == false || (x.IsContextual && x.Group.Visibility == Visibility.Visible))) - .OrderBy(x => x.IsContextual) - .ToList(); -#else - var tabs = this.Items.OfType().Select(x => this.ItemContainerGenerator.ContainerFromItem(x)).OfType() - .Where(x => x.Visibility == Visibility.Visible && (x.IsContextual == false || (x.IsContextual && x.Group.Visibility == Visibility.Visible))) - .OrderBy(x => x.IsContextual) - .ToList(); -#endif - - for (var i = 0; i < tabs.Count; i++) - { - var ribbonTabItem = tabs[i]; - visualItems.Add(ribbonTabItem); - - if (ribbonTabItem.IsSelected) - { - selectedIndex = visualItems.Count - 1; - } - } - - if (e.Delta > 0) - { - if (selectedIndex > 0) - { - visualItems[selectedIndex].IsSelected = false; - selectedIndex--; - visualItems[selectedIndex].IsSelected = true; - } - } - else if (e.Delta < 0) - { - if (selectedIndex < visualItems.Count - 1) - { - visualItems[selectedIndex].IsSelected = false; - selectedIndex++; - visualItems[selectedIndex].IsSelected = true; - } - } - - e.Handled = true; - } - - // Get selected ribbon tab item - private RibbonTabItem GetSelectedTabItem() - { - var selectedItem = this.SelectedItem; - if (selectedItem == null) - { - return null; - } - - var item = selectedItem as RibbonTabItem - ?? this.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex) as RibbonTabItem; - - return item; - } - - // Find next tab item - private RibbonTabItem FindNextTabItem(int startIndex, int direction) - { - if (direction != 0) - { - var index = startIndex; - for (var i = 0; i < this.Items.Count; i++) - { - index += direction; - - if (index >= this.Items.Count) - { - index = 0; - } - else if (index < 0) - { - index = this.Items.Count - 1; - } - - var nextItem = this.ItemContainerGenerator.ContainerFromIndex(index) as RibbonTabItem; - if (((nextItem != null) && nextItem.IsEnabled) && (nextItem.Visibility == Visibility.Visible)) - { - return nextItem; - } - } - } - - return null; - } - - // Updates selected content - private void UpdateSelectedContent() - { - if (this.SelectedIndex < 0) - { - this.SelectedContent = null; - this.SelectedTabItem = null; - } - else - { - var selectedTabItem = this.GetSelectedTabItem(); - if (selectedTabItem != null) - { - this.SelectedContent = selectedTabItem.GroupsContainer; - this.SelectedTabItem = selectedTabItem; - } - } - } - - #endregion - - #region Event handling - - private void OnLoaded(object sender, RoutedEventArgs e) - { - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - } - - // Handles GeneratorStatus changed - private void OnGeneratorStatusChanged(object sender, EventArgs e) - { - if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) - { - this.UpdateSelectedContent(); - } - } - - // Handles IsMinimized changed - private static void OnMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var tab = (RibbonTabControl)d; - - if (!tab.IsMinimized) - { - tab.IsDropDownOpen = false; - } - - if ((bool)e.NewValue == false - && tab.SelectedIndex < 0) - { - var item = tab.FindNextTabItem(-1, 1); - - if (item != null) - { - item.IsSelected = true; - } - } - } - - // Handles ribbon popup closing - private void OnRibbonTabPopupClosing() - { - var ribbonTabItem = this.SelectedItem as RibbonTabItem; - - if (ribbonTabItem != null) - { - ribbonTabItem.IsHitTestVisible = true; - } - - if (Mouse.Captured == this) - { - Mouse.Capture(null); - } - } - - // handles ribbon popup opening - private void OnRibbonTabPopupOpening() - { - var ribbonTabItem = this.SelectedItem as RibbonTabItem; - - if (ribbonTabItem != null) - { - ribbonTabItem.IsHitTestVisible = false; - } - - Mouse.Capture(this, CaptureMode.SubTree); - } - - /// - /// Implements custom placement for ribbon popup - /// - /// - /// - /// - /// - private CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset) - { - if (this.DropDownPopup == null - || this.SelectedTabItem == null) - { - return null; - } - - // Get current workarea - var tabItemPos = this.SelectedTabItem.PointToScreen(new Point(0, 0)); - var tabItemRect = new RECT - { - left = (int)tabItemPos.X, - top = (int)tabItemPos.Y, - right = (int)tabItemPos.X + (int)this.SelectedTabItem.ActualWidth, - bottom = (int)tabItemPos.Y + (int)this.SelectedTabItem.ActualHeight - }; - - const uint MONITOR_DEFAULTTONEAREST = 0x00000002; - - var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); - if (monitor == IntPtr.Zero) - { - return null; - } - - var monitorInfo = new MONITORINFO(); - monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); - UnsafeNativeMethods.GetMonitorInfo(monitor, monitorInfo); - - var startPoint = this.PointToScreen(new Point(0, 0)); - if (this.FlowDirection == FlowDirection.RightToLeft) - { - startPoint.X -= this.ActualWidth; - } - - var inWindowRibbonWidth = monitorInfo.rcWork.right - Math.Max(monitorInfo.rcWork.left, startPoint.X); - - var actualWidth = this.ActualWidth; - if (startPoint.X < monitorInfo.rcWork.left) - { - actualWidth -= monitorInfo.rcWork.left - startPoint.X; - startPoint.X = monitorInfo.rcWork.left; - } - - // Set width and prevent negative values - this.DropDownPopup.Width = Math.Max(0, Math.Min(actualWidth, inWindowRibbonWidth)); - return new[] - { - new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X + offset.X, targetsize.Height + offset.Y), PopupPrimaryAxis.Vertical), - new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X + offset.X, -1 * (targetsize.Height + offset.Y + ((ScrollViewer)this.SelectedContent).ActualHeight)), PopupPrimaryAxis.Vertical) - }; - } - - // Handles IsDropDownOpen property changed - private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var ribbonTabControl = (RibbonTabControl)d; - - ribbonTabControl.RaiseRequestBackstageClose(); - - if (ribbonTabControl.IsDropDownOpen) - { - ribbonTabControl.OnRibbonTabPopupOpening(); - } - else - { - ribbonTabControl.OnRibbonTabPopupClosing(); - } - } - - /// - /// Raises an event causing the Backstage-View to be closed - /// - public void RaiseRequestBackstageClose() - { - var handler = this.RequestBackstageClose; - - if (handler != null) - { - handler(this, null); - } - } - - #endregion - - /// - /// Gets the first visible item - /// - public object GetFirstVisibleItem() - { - foreach (var item in this.Items) - { - var ribbonTab = this.ItemContainerGenerator.ContainerFromItem(item) as RibbonTabItem; - - if (ribbonTab != null - && ribbonTab.Visibility == Visibility.Visible) - { - return ribbonTab; - } - } - - return null; - } - } +namespace Fluent +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Input; + using System.Windows.Media; + using Fluent.Metro.Native; + + /// + /// Represents ribbon tab control + /// + [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonTabItem))] + [TemplatePart(Name = "PART_Popup", Type = typeof(Popup))] + [TemplatePart(Name = "PART_TabsContainer", Type = typeof(IScrollInfo))] + [TemplatePart(Name = "PART_ToolbarPanel", Type = typeof(Panel))] + public class RibbonTabControl : Selector, IDropDownControl + { + #region Fields + + // Collection of toolbar items + private ObservableCollection toolBarItems; + + // ToolBar panel + private Panel toolbarPanel; + + #endregion + + #region Events + + /// + /// Event which is fired when the, maybe listening, should be closed + /// + public event EventHandler RequestBackstageClose; + + #endregion + + #region Properties + + #region Menu + + /// + /// Gets or sets file menu control (can be application menu button, backstage button and so on) + /// + public UIElement Menu + { + get { return (UIElement)this.GetValue(MenuProperty); } + set { this.SetValue(MenuProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Button. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MenuProperty = + DependencyProperty.Register("Menu", typeof(UIElement), + typeof(RibbonTabControl), new UIPropertyMetadata(null)); + + #endregion + + /// + /// Gets drop down popup + /// + public Popup DropDownPopup { get; private set; } + + /// + /// Gets a value indicating whether context menu is opened + /// + public bool IsContextMenuOpened { get; set; } + + /// + /// Gets content of selected tab item + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public object SelectedContent + { + get + { + return this.GetValue(SelectedContentProperty); + } + internal set + { + this.SetValue(SelectedContentPropertyKey, value); + } + } + + // DependencyProperty key for SelectedContent + static readonly DependencyPropertyKey SelectedContentPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContent", typeof(object), typeof(RibbonTabControl), new FrameworkPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectedContentProperty = SelectedContentPropertyKey.DependencyProperty; + + /// + /// Gets or sets whether ribbon is minimized + /// + public bool IsMinimized + { + get { return (bool)this.GetValue(IsMinimizedProperty); } + set { this.SetValue(IsMinimizedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsMinimizedProperty = DependencyProperty.Register("IsMinimized", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(false, OnMinimizedChanged)); + + /// + /// Gets or sets whether ribbon can be minimized + /// + public bool CanMinimize + { + get { return (bool)this.GetValue(CanMinimizeProperty); } + set { this.SetValue(CanMinimizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanMinimizeProperty = DependencyProperty.Register("CanMinimize", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(true)); + + + /// + /// Gets or sets whether ribbon popup is opened + /// + public bool IsDropDownOpen + { + get { return (bool)this.GetValue(IsDropDownOpenProperty); } + set { this.SetValue(IsDropDownOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(false, OnIsDropDownOpenChanged, CoerceIsDropDownOpen)); + + private static object CoerceIsDropDownOpen(DependencyObject d, object basevalue) + { + var tabControl = d as RibbonTabControl; + + if (tabControl == null) + { + return basevalue; + } + + if (!tabControl.IsMinimized) + { + return false; + } + + return basevalue; + } + + /// + /// Defines if the currently selected item should draw it's highlight/selected borders + /// + public bool HighlightSelectedItem + { + get { return (bool)this.GetValue(HighlightSelectedItemProperty); } + set { this.SetValue(HighlightSelectedItemProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HighlightSelectedItemProperty = + DependencyProperty.RegisterAttached("HighlightSelectedItem", typeof(bool), typeof(RibbonTabControl), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// Gets whether ribbon tabs can scroll + /// + internal bool CanScroll + { + get + { + var scrollInfo = this.GetTemplateChild("PART_TabsContainer") as IScrollInfo; + if (scrollInfo != null) + { + return scrollInfo.ExtentWidth > scrollInfo.ViewportWidth; + } + + return false; + } + } + + /// + /// Gets or sets selected tab item + /// + internal RibbonTabItem SelectedTabItem + { + get { return (RibbonTabItem)this.GetValue(SelectedTabItemProperty); } + private set { this.SetValue(SelectedTabItemProperty, value); } + } + + // Using a DependencyProperty as the backing store for SelectedTabItem. This enables animation, styling, binding, etc... + internal static readonly DependencyProperty SelectedTabItemProperty = + DependencyProperty.Register("SelectedTabItem", typeof(RibbonTabItem), typeof(RibbonTabControl), new UIPropertyMetadata(null)); + + /// + /// Gets collection of ribbon toolbar items + /// + public ObservableCollection ToolBarItems + { + get + { + if (this.toolBarItems == null) + { + this.toolBarItems = new ObservableCollection(); + this.toolBarItems.CollectionChanged += this.OnToolbarItemsCollectionChanged; + } + + return this.toolBarItems; + } + } + + internal Panel ToolbarPanel + { + get { return this.toolbarPanel; } + } + + // Handle toolbar iitems changes + private void OnToolbarItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (this.ToolbarPanel == null) + { + return; + } + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (var i = 0; i < e.NewItems.Count; i++) + { + this.ToolbarPanel.Children.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var obj3 in e.OldItems.OfType()) + { + this.ToolbarPanel.Children.Remove(obj3); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var obj4 in e.OldItems.OfType()) + { + this.ToolbarPanel.Children.Remove(obj4); + } + foreach (var obj5 in e.NewItems.OfType()) + { + this.ToolbarPanel.Children.Add(obj5); + } + break; + + case NotifyCollectionChangedAction.Reset: + this.toolbarPanel.Children.Clear(); + foreach (var toolBarItem in this.ToolBarItems) + { + this.ToolbarPanel.Children.Add(toolBarItem); + } + break; + } + + } + + /// + /// Gets or sets the height of the gap between the ribbon and the content + /// + public double ContentGapHeight + { + get { return (double)this.GetValue(ContentGapHeightProperty); } + set { this.SetValue(ContentGapHeightProperty, value); } + } + + /// + /// DependencyProperty for + /// + public static readonly DependencyProperty ContentGapHeightProperty = + DependencyProperty.Register("ContentGapHeight", typeof(double), typeof(RibbonTabControl), new UIPropertyMetadata(5D)); + + #endregion + + #region Initializion + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonTabControl() + { + var type = typeof(RibbonTabControl); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(typeof(RibbonTabControl))); + ContextMenuService.Attach(type); + PopupService.Attach(type); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = ((FrameworkElement)d).TryFindResource(typeof(RibbonTabControl)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public RibbonTabControl() + { + ContextMenuService.Coerce(this); + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + #endregion + + #region Overrides + + /// + /// Raises the System.Windows.FrameworkElement.Initialized event. + /// This method is invoked whenever System.Windows. + /// FrameworkElement.IsInitialized is set to true internally. + /// + /// The System.Windows.RoutedEventArgs that contains the event data. + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + this.ItemContainerGenerator.StatusChanged += this.OnGeneratorStatusChanged; + } + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new RibbonTabItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// true if the item is (or is eligible to be) its own container; otherwise, false. + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is RibbonTabItem; + } + + /// + /// When overridden in a derived class, is invoked whenever application code or + /// internal processes call System.Windows.FrameworkElement.ApplyTemplate(). + /// + public override void OnApplyTemplate() + { + this.DropDownPopup = this.Template.FindName("PART_Popup", this) as Popup; + if (this.DropDownPopup != null) + { + this.DropDownPopup.CustomPopupPlacementCallback = this.CustomPopupPlacementMethod; + } + + if (this.ToolbarPanel != null + && this.toolBarItems != null) + { + for (var i = 0; i < this.toolBarItems.Count; i++) + { + this.ToolbarPanel.Children.Remove(this.toolBarItems[i]); + } + } + + this.toolbarPanel = this.Template.FindName("PART_ToolbarPanel", this) as Panel; + + if (this.ToolbarPanel != null + && this.toolBarItems != null) + { + for (var i = 0; i < this.toolBarItems.Count; i++) + { + this.ToolbarPanel.Children.Add(this.toolBarItems[i]); + } + } + } + + /// + /// Updates the current selection when an item in the System.Windows.Controls.Primitives.Selector has changed + /// + /// The event data. + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (this.IsMinimized + && this.IsDropDownOpen == false) + { + return; + } + + if (e.Action == NotifyCollectionChangedAction.Remove + && this.SelectedIndex == -1) + { + var startIndex = e.OldStartingIndex + 1; + if (startIndex > this.Items.Count) + { + startIndex = 0; + } + + var item = this.FindNextTabItem(startIndex, -1); + if (item != null) + { + item.IsSelected = true; + } + else + { + this.SelectedContent = null; + } + } + } + + /// + /// Called when the selection changes. + /// + /// The event data. + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + this.UpdateSelectedContent(); + + if (e.AddedItems.Count > 0) + { + if (this.IsMinimized) + { + this.IsDropDownOpen = true; + + ((RibbonTabItem)e.AddedItems[0]).IsHitTestVisible = false; + } + } + else + { + if (this.IsDropDownOpen) + { + this.IsDropDownOpen = false; + } + } + + if (e.RemovedItems.Count > 0) + { + ((RibbonTabItem)e.RemovedItems[0]).IsHitTestVisible = true; + } + + base.OnSelectionChanged(e); + } + + /// + /// Invoked when an unhandled System.Windows.Input.Mouse.PreviewMouseWheel  + /// attached event reaches an element in its route that is derived from this class. + /// Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseWheelEventArgs that contains the event data. + protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) + { + //base.OnPreviewMouseWheel(e); + this.ProcessMouseWheel(e); + } + + /// + /// Invoked when the event is received. + /// + /// Information about the event. + protected override void OnKeyDown(KeyEventArgs e) + { + this.OnKeyUp(e); + + if (e.Handled) + { + return; + } + + switch (e.Key) + { + case Key.Escape: + if (this.IsDropDownOpen) + { + this.IsDropDownOpen = false; + } + break; + } + } + + #endregion + + #region Private methods + + private static bool IsRibbonAncestorOf(DependencyObject element) + { + while (element != null) + { + if (element is Ribbon) + { + return true; + } + + var parent = LogicalTreeHelper.GetParent(element) ?? VisualTreeHelper.GetParent(element); + + element = parent; + } + + return false; + } + + // Process mouse wheel event + internal void ProcessMouseWheel(MouseWheelEventArgs e) + { + if (this.IsMinimized + || this.SelectedItem == null) + { + return; + } + + var focusedElement = Keyboard.FocusedElement as DependencyObject; + + if (focusedElement != null + && IsRibbonAncestorOf(focusedElement)) + { + return; + } + + var visualItems = new List(); + var selectedIndex = -1; + +#if NET45 + var tabs = this.ItemContainerGenerator.Items.OfType() + .Where(x => x.Visibility == Visibility.Visible && (x.IsContextual == false || (x.IsContextual && x.Group.Visibility == Visibility.Visible))) + .OrderBy(x => x.IsContextual) + .ToList(); +#else + var tabs = this.Items.OfType().Select(x => this.ItemContainerGenerator.ContainerFromItem(x)).OfType() + .Where(x => x.Visibility == Visibility.Visible && (x.IsContextual == false || (x.IsContextual && x.Group.Visibility == Visibility.Visible))) + .OrderBy(x => x.IsContextual) + .ToList(); +#endif + + for (var i = 0; i < tabs.Count; i++) + { + var ribbonTabItem = tabs[i]; + visualItems.Add(ribbonTabItem); + + if (ribbonTabItem.IsSelected) + { + selectedIndex = visualItems.Count - 1; + } + } + + if (e.Delta > 0) + { + if (selectedIndex > 0) + { + visualItems[selectedIndex].IsSelected = false; + selectedIndex--; + visualItems[selectedIndex].IsSelected = true; + } + } + else if (e.Delta < 0) + { + if (selectedIndex < visualItems.Count - 1) + { + visualItems[selectedIndex].IsSelected = false; + selectedIndex++; + visualItems[selectedIndex].IsSelected = true; + } + } + + e.Handled = true; + } + + // Get selected ribbon tab item + private RibbonTabItem GetSelectedTabItem() + { + var selectedItem = this.SelectedItem; + if (selectedItem == null) + { + return null; + } + + var item = selectedItem as RibbonTabItem + ?? this.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex) as RibbonTabItem; + + return item; + } + + // Find next tab item + private RibbonTabItem FindNextTabItem(int startIndex, int direction) + { + if (direction != 0) + { + var index = startIndex; + for (var i = 0; i < this.Items.Count; i++) + { + index += direction; + + if (index >= this.Items.Count) + { + index = 0; + } + else if (index < 0) + { + index = this.Items.Count - 1; + } + + var nextItem = this.ItemContainerGenerator.ContainerFromIndex(index) as RibbonTabItem; + if (((nextItem != null) && nextItem.IsEnabled) && (nextItem.Visibility == Visibility.Visible)) + { + return nextItem; + } + } + } + + return null; + } + + // Updates selected content + private void UpdateSelectedContent() + { + if (this.SelectedIndex < 0) + { + this.SelectedContent = null; + this.SelectedTabItem = null; + } + else + { + var selectedTabItem = this.GetSelectedTabItem(); + if (selectedTabItem != null) + { + this.SelectedContent = selectedTabItem.GroupsContainer; + this.SelectedTabItem = selectedTabItem; + } + } + } + + #endregion + + #region Event handling + + private void OnLoaded(object sender, RoutedEventArgs e) + { + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + } + + // Handles GeneratorStatus changed + private void OnGeneratorStatusChanged(object sender, EventArgs e) + { + if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) + { + this.UpdateSelectedContent(); + } + } + + // Handles IsMinimized changed + private static void OnMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var tab = (RibbonTabControl)d; + + if (!tab.IsMinimized) + { + tab.IsDropDownOpen = false; + } + + if ((bool)e.NewValue == false + && tab.SelectedIndex < 0) + { + var item = tab.FindNextTabItem(-1, 1); + + if (item != null) + { + item.IsSelected = true; + } + } + } + + // Handles ribbon popup closing + private void OnRibbonTabPopupClosing() + { + var ribbonTabItem = this.SelectedItem as RibbonTabItem; + + if (ribbonTabItem != null) + { + ribbonTabItem.IsHitTestVisible = true; + } + + if (Mouse.Captured == this) + { + Mouse.Capture(null); + } + } + + // handles ribbon popup opening + private void OnRibbonTabPopupOpening() + { + var ribbonTabItem = this.SelectedItem as RibbonTabItem; + + if (ribbonTabItem != null) + { + ribbonTabItem.IsHitTestVisible = false; + } + + Mouse.Capture(this, CaptureMode.SubTree); + } + + /// + /// Implements custom placement for ribbon popup + /// + /// + /// + /// + /// + private CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupsize, Size targetsize, Point offset) + { + if (this.DropDownPopup == null + || this.SelectedTabItem == null) + { + return null; + } + + // Get current workarea + var tabItemPos = this.SelectedTabItem.PointToScreen(new Point(0, 0)); + var tabItemRect = new RECT + { + left = (int)tabItemPos.X, + top = (int)tabItemPos.Y, + right = (int)tabItemPos.X + (int)this.SelectedTabItem.ActualWidth, + bottom = (int)tabItemPos.Y + (int)this.SelectedTabItem.ActualHeight + }; + + const uint MONITOR_DEFAULTTONEAREST = 0x00000002; + + var monitor = NativeMethods.MonitorFromRect(ref tabItemRect, MONITOR_DEFAULTTONEAREST); + if (monitor == IntPtr.Zero) + { + return null; + } + + var monitorInfo = new MONITORINFO(); + monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); + NativeMethods.GetMonitorInfo(monitor, monitorInfo); + + var startPoint = this.PointToScreen(new Point(0, 0)); + if (this.FlowDirection == FlowDirection.RightToLeft) + { + startPoint.X -= this.ActualWidth; + } + + var inWindowRibbonWidth = monitorInfo.rcWork.right - Math.Max(monitorInfo.rcWork.left, startPoint.X); + + var actualWidth = this.ActualWidth; + if (startPoint.X < monitorInfo.rcWork.left) + { + actualWidth -= monitorInfo.rcWork.left - startPoint.X; + startPoint.X = monitorInfo.rcWork.left; + } + + // Set width and prevent negative values + this.DropDownPopup.Width = Math.Max(0, Math.Min(actualWidth, inWindowRibbonWidth)); + return new[] + { + new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X + offset.X, targetsize.Height + offset.Y), PopupPrimaryAxis.Vertical), + new CustomPopupPlacement(new Point(startPoint.X - tabItemPos.X + offset.X, -1 * (targetsize.Height + offset.Y + ((ScrollViewer)this.SelectedContent).ActualHeight)), PopupPrimaryAxis.Vertical) + }; + } + + // Handles IsDropDownOpen property changed + private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbonTabControl = (RibbonTabControl)d; + + ribbonTabControl.RaiseRequestBackstageClose(); + + if (ribbonTabControl.IsDropDownOpen) + { + ribbonTabControl.OnRibbonTabPopupOpening(); + } + else + { + ribbonTabControl.OnRibbonTabPopupClosing(); + } + } + + /// + /// Raises an event causing the Backstage-View to be closed + /// + public void RaiseRequestBackstageClose() + { + var handler = this.RequestBackstageClose; + + if (handler != null) + { + handler(this, null); + } + } + + #endregion + + /// + /// Gets the first visible item + /// + public object GetFirstVisibleItem() + { + foreach (var item in this.Items) + { + var ribbonTab = this.ItemContainerGenerator.ContainerFromItem(item) as RibbonTabItem; + + if (ribbonTab != null + && ribbonTab.Visibility == Visibility.Visible) + { + return ribbonTab; + } + } + + return null; + } + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonTabItem.cs b/Fluent.Ribbon/Controls/RibbonTabItem.cs similarity index 94% rename from Fluent/Controls/RibbonTabItem.cs rename to Fluent.Ribbon/Controls/RibbonTabItem.cs index 128add225..aeebc1da8 100644 --- a/Fluent/Controls/RibbonTabItem.cs +++ b/Fluent.Ribbon/Controls/RibbonTabItem.cs @@ -1,754 +1,752 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - using System.Linq; - using System.Windows.Data; - - /// - /// Represents ribbon tab item - /// - [TemplatePart(Name = "PART_ContentContainer", Type = typeof(Border))] - [ContentProperty("Groups")] - [DefaultProperty("Groups")] - [DefaultEvent("IsSelectedChanged")] - public class RibbonTabItem : Control, IKeyTipedControl, IHeaderedControl - { - #region Fields - - // Content container - private Border contentContainer; - - // Desired width - private double desiredWidth; - - // Collection of ribbon groups - private ObservableCollection groups; - - // Ribbon groups container - private readonly RibbonGroupsContainer groupsInnerContainer = new RibbonGroupsContainer(); - private readonly ScrollViewer groupsContainer = new ScrollViewer(); - - // Cached width - private double cachedWidth; - - #endregion - - #region Properties - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonTabItem)); - - #endregion - - /// - /// Gets ribbon groups container - /// - public ScrollViewer GroupsContainer - { - get { return this.groupsContainer; } - } - - /// - /// Gets or sets whether ribbon is minimized - /// - public bool IsMinimized - { - get { return (bool)this.GetValue(IsMinimizedProperty); } - set { this.SetValue(IsMinimizedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsMinimized. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsMinimizedProperty = DependencyProperty.Register("IsMinimized", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// Gets or sets whether ribbon is opened - /// - public bool IsOpen - { - get { return (bool)this.GetValue(IsOpenProperty); } - set { this.SetValue(IsOpenProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsOpen. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// Gets or sets reduce order - /// - public string ReduceOrder - { - get { return this.groupsInnerContainer.ReduceOrder; } - set { this.groupsInnerContainer.ReduceOrder = value; } - } - - #region IsContextual - - /// - /// Gets or sets whether tab item is contextual - /// - public bool IsContextual - { - get { return (bool)this.GetValue(IsContextualProperty); } - private set { this.SetValue(IsContextualPropertyKey, value); } - } - - private static readonly DependencyPropertyKey IsContextualPropertyKey = - DependencyProperty.RegisterReadOnly("IsContextual", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for IsContextual. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsContextualProperty = IsContextualPropertyKey.DependencyProperty; - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - yield return this.groupsContainer; - } - } - - #endregion - - /// - /// Gets or sets whether tab item is selected - /// - [Bindable(true), Category("Appearance")] - public bool IsSelected - { - get - { - return (bool)this.GetValue(IsSelectedProperty); - } - set - { - this.SetValue(IsSelectedProperty, value); - } - } - - /// - /// Using a DependencyProperty as the backing store for IsSelected. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsParentMeasure, new PropertyChangedCallback(OnIsSelectedChanged))); - - /// - /// Gets ribbon tab control parent - /// - internal RibbonTabControl TabControlParent - { - get - { - return (ItemsControl.ItemsControlFromItemContainer(this) as RibbonTabControl); - } - } - - - /// - /// Gets or sets indent - /// - public double Indent - { - get { return (double)this.GetValue(IndentProperty); } - set { this.SetValue(IndentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HeaderMargin. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IndentProperty = - DependencyProperty.Register("Indent", typeof(double), typeof(RibbonTabItem), new UIPropertyMetadata((double)12.0)); - - /// - /// Gets or sets whether separator is visible - /// - public bool IsSeparatorVisible - { - get { return (bool)this.GetValue(IsSeparatorVisibleProperty); } - set { this.SetValue(IsSeparatorVisibleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsSeparatorVisible. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsSeparatorVisibleProperty = - DependencyProperty.Register("IsSeparatorVisible", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// Gets or sets ribbon contextual tab group - /// - public RibbonContextualTabGroup Group - { - get { return (RibbonContextualTabGroup)this.GetValue(GroupProperty); } - set { this.SetValue(GroupProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Group. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupProperty = - DependencyProperty.Register("Group", typeof(RibbonContextualTabGroup), typeof(RibbonTabItem), new UIPropertyMetadata(null, OnGroupChanged)); - - // handles Group property chanhged - private static void OnGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var tab = (RibbonTabItem)d; - - if (e.OldValue != null) - { - ((RibbonContextualTabGroup)e.OldValue).RemoveTabItem(tab); - } - - if (e.NewValue != null) - { - var tabGroup = (RibbonContextualTabGroup)e.NewValue; - tabGroup.AppendTabItem(tab); - tab.IsContextual = true; - } - else - { - tab.IsContextual = false; - } - } - - /// - /// Gets or sets desired width of the tab item - /// - internal double DesiredWidth - { - get { return this.desiredWidth; } - set - { - this.desiredWidth = value; - this.InvalidateMeasure(); - } - } - - /// - /// Gets or sets whether tab item has left group border - /// - public bool HasLeftGroupBorder - { - get { return (bool)this.GetValue(HasLeftGroupBorderProperty); } - set { this.SetValue(HasLeftGroupBorderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HaseLeftGroupBorder. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasLeftGroupBorderProperty = - DependencyProperty.Register("HasLeftGroupBorder", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// Gets or sets whether tab item has right group border - /// - public bool HasRightGroupBorder - { - get { return (bool)this.GetValue(HasRightGroupBorderProperty); } - set { this.SetValue(HasRightGroupBorderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HaseLeftGroupBorder. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasRightGroupBorderProperty = - DependencyProperty.Register("HasRightGroupBorder", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); - - /// - /// get collection of ribbon groups - /// - public ObservableCollection Groups - { - get - { - if (this.groups == null) - { - this.groups = new ObservableCollection(); - this.groups.CollectionChanged += this.OnGroupsCollectionChanged; - } - return this.groups; - } - } - - // handles ribbon groups collection changes - private void OnGroupsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (this.groupsInnerContainer == null) - { - return; - } - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - for (int i = 0; i < e.NewItems.Count; i++) - { - this.groupsInnerContainer.Children.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); - } - break; - - case NotifyCollectionChangedAction.Remove: - foreach (var item in e.OldItems.OfType()) - { - this.groupsInnerContainer.Children.Remove(item); - } - break; - - case NotifyCollectionChangedAction.Replace: - foreach (var item in e.OldItems.OfType()) - { - this.groupsInnerContainer.Children.Remove(item); - } - foreach (var item in e.NewItems.OfType()) - { - this.groupsInnerContainer.Children.Add(item); - } - break; - - case NotifyCollectionChangedAction.Reset: - this.groupsInnerContainer.Children.Clear(); - - foreach (var group in this.groups) - { - this.groupsInnerContainer.Children.Add(group); - } - break; - } - - } - - #region Header Property - - /// - /// Gets or sets header of tab item - /// - public object Header - { - get { return (object)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = - DependencyProperty.Register("Header", typeof(object), typeof(RibbonTabItem), new UIPropertyMetadata(null, OnHeaderChanged)); - - // Header changed handler - static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonTabItem tabItem = (RibbonTabItem)d; - tabItem.CoerceValue(ToolTipProperty); - } - - #endregion - - #region Focusable - - /// - /// Handles IsEnabled changes - /// - /// - /// The event data. - private static void OnFocusableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - } - - /// - /// Coerces IsEnabled - /// - /// - /// - /// - private static object CoerceFocusable(DependencyObject d, object basevalue) - { - var control = d as RibbonTabItem; - if (control != null) - { - var ribbon = control.FindParentRibbon(); - if (ribbon != null) - { - return ((bool)basevalue) - && ribbon.Focusable; - } - } - - return basevalue; - } - - // Find parent ribbon - private Ribbon FindParentRibbon() - { - var element = this.Parent; - while (element != null) - { - var ribbon = element as Ribbon; - if (ribbon != null) - { - return ribbon; - } - - element = VisualTreeHelper.GetParent(element); - } - - return null; - } - - #endregion - - #endregion - - #region Initialize - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonTabItem() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(typeof(RibbonTabItem))); - FocusableProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(OnFocusableChanged, CoerceFocusable)); - ToolTipProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(null, CoerceToolTip)); - VisibilityProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(OnVisibilityChanged)); - StyleProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonTabItem)); - } - - return basevalue; - } - - // Handles visibility changes - private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var item = d as RibbonTabItem; - - if (item == null) - { - return; - } - - if (item.Group != null) - { - item.Group.UpdateInnerVisiblityAndGroupBorders(); - } - - if (item.IsSelected - && (Visibility)e.NewValue == Visibility.Collapsed) - { - if (item.TabControlParent != null) - { - if (item.TabControlParent.IsMinimized) - { - item.IsSelected = false; - } - else - { - item.TabControlParent.SelectedItem = item.TabControlParent.GetFirstVisibleItem(); - } - } - } - } - - // Coerce ToolTip to ensure that tooltip displays name of the tabitem - private static object CoerceToolTip(DependencyObject d, object basevalue) - { - var tabItem = (RibbonTabItem)d; - if (basevalue == null - && tabItem.Header is string) - { - basevalue = tabItem.Header; - } - - return basevalue; - } - - /// - /// Default constructor - /// - public RibbonTabItem() - { - this.AddLogicalChild(this.groupsContainer); - this.groupsContainer.Content = this.groupsInnerContainer; - - // Force redirection of DataContext. This is needed, because we detach the container from the visual tree and attach it to a diffrent one (the popup/dropdown) when the ribbon is minimized. - this.groupsInnerContainer.SetBinding(DataContextProperty, new Binding("DataContext") - { - Source = this - }); - - ContextMenuService.Coerce(this); - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - #endregion - - #region Overrides - - /// - /// Called to remeasure a control. - /// - /// The maximum size that the method can return. - /// The size of the control, up to the maximum specified by constraint. - protected override Size MeasureOverride(Size constraint) - { - if (this.contentContainer == null) - { - return base.MeasureOverride(constraint); - } - - if (this.IsContextual && this.Group != null && this.Group.Visibility == Visibility.Collapsed) - { - return Size.Empty; - } - - this.contentContainer.Padding = new Thickness(this.Indent, this.contentContainer.Padding.Top, this.Indent, this.contentContainer.Padding.Bottom); - Size baseConstraint = base.MeasureOverride(constraint); - double totalWidth = this.contentContainer.DesiredSize.Width - this.contentContainer.Margin.Left - this.contentContainer.Margin.Right; - (this.contentContainer.Child).Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - double headerWidth = this.contentContainer.Child.DesiredSize.Width; - if (totalWidth < headerWidth + this.Indent * 2) - { - double newPaddings = Math.Max(0, (totalWidth - headerWidth) / 2); - this.contentContainer.Padding = new Thickness(newPaddings, this.contentContainer.Padding.Top, newPaddings, this.contentContainer.Padding.Bottom); - } - else - { - if (this.desiredWidth != 0) - { - // If header width is larger then tab increase tab width - if ((constraint.Width > this.desiredWidth) && (this.desiredWidth > totalWidth)) baseConstraint.Width = this.desiredWidth; - else - baseConstraint.Width = headerWidth + this.Indent * 2 + this.contentContainer.Margin.Left + this.contentContainer.Margin.Right; - } - } - - if ((this.cachedWidth != baseConstraint.Width) && (this.IsContextual) && (this.Group != null)) - { - this.cachedWidth = baseConstraint.Width; - FrameworkElement parent = (VisualTreeHelper.GetParent(this.Group) as FrameworkElement); - if (parent != null) parent.InvalidateMeasure(); - } - - return baseConstraint; - } - - /// - /// On new style applying - /// - public override void OnApplyTemplate() - { - this.contentContainer = this.GetTemplateChild("PART_ContentContainer") as Border; - } - - /// - /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonDownrouted event is raised - /// on this element. Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) - { - if (e.Source == this - && e.ClickCount == 2) - { - e.Handled = true; - - if (this.TabControlParent != null) - { - this.TabControlParent.IsMinimized = !this.TabControlParent.IsMinimized; - } - } - else if (e.Source == this - || !this.IsSelected) - { - if (this.Visibility == Visibility.Visible) - { - if (this.TabControlParent != null) - { - var newItem = this.TabControlParent.ItemContainerGenerator.ItemFromContainer(this); - - if (this.TabControlParent.SelectedTabItem == newItem) - { - this.TabControlParent.IsDropDownOpen = !this.TabControlParent.IsDropDownOpen; - } - else - { - this.TabControlParent.SelectedItem = newItem; - } - - this.TabControlParent.RaiseRequestBackstageClose(); - } - else - { - this.IsSelected = true; - } - - e.Handled = true; - } - } - } - - #endregion - - #region Private methods - - // Handles IsSelected property changes - private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonTabItem container = d as RibbonTabItem; - bool newValue = (bool)e.NewValue; - if (newValue) - { - if ((container.TabControlParent != null) && (container.TabControlParent.SelectedItem is RibbonTabItem) && (container.TabControlParent.SelectedItem != container)) - (container.TabControlParent.SelectedItem as RibbonTabItem).IsSelected = false; - container.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, container)); - } - else - { - container.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, container)); - } - - } - /// - /// Handles selected - /// - /// The event data - protected virtual void OnSelected(RoutedEventArgs e) - { - this.HandleIsSelectedChanged(e); - } - /// - /// handles unselected - /// - /// The event data - protected virtual void OnUnselected(RoutedEventArgs e) - { - this.HandleIsSelectedChanged(e); - } - - #endregion - - #region Event handling - - // Handles IsSelected property changes - private void HandleIsSelectedChanged(RoutedEventArgs e) - { - this.RaiseEvent(e); - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.SubscribeEvents(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.UnSubscribeEvents(); - } - - private void SubscribeEvents() - { - // Always unsubscribe events to ensure we don't subscribe twice - this.UnSubscribeEvents(); - - if (this.groups != null) - { - this.groups.CollectionChanged += this.OnGroupsCollectionChanged; - } - } - - private void UnSubscribeEvents() - { - if (this.groups != null) - { - this.groups.CollectionChanged -= this.OnGroupsCollectionChanged; - } - } - - #endregion - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - if (this.TabControlParent != null) - { - var currentSelectedItem = this.TabControlParent.SelectedItem as RibbonTabItem; - - if (currentSelectedItem != null) - { - currentSelectedItem.IsSelected = false; - } - } - - this.IsSelected = true; - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - if (this.TabControlParent != null - && this.TabControlParent.IsMinimized) - { - this.TabControlParent.IsDropDownOpen = false; - } - } - } +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; + +namespace Fluent +{ + using System.Linq; + using System.Windows.Data; + + /// + /// Represents ribbon tab item + /// + [TemplatePart(Name = "PART_ContentContainer", Type = typeof(Border))] + [ContentProperty("Groups")] + [DefaultProperty("Groups")] + [DefaultEvent("IsSelectedChanged")] + public class RibbonTabItem : Control, IKeyTipedControl, IHeaderedControl + { + #region Fields + + // Content container + private Border contentContainer; + + // Desired width + private double desiredWidth; + + // Collection of ribbon groups + private ObservableCollection groups; + + // Ribbon groups container + private readonly RibbonGroupsContainer groupsInnerContainer = new RibbonGroupsContainer(); + private readonly ScrollViewer groupsContainer = new ScrollViewer(); + + // Cached width + private double cachedWidth; + + #endregion + + #region Properties + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(RibbonTabItem)); + + #endregion + + /// + /// Gets ribbon groups container + /// + public ScrollViewer GroupsContainer + { + get { return this.groupsContainer; } + } + + /// + /// Gets or sets whether ribbon is minimized + /// + public bool IsMinimized + { + get { return (bool)this.GetValue(IsMinimizedProperty); } + set { this.SetValue(IsMinimizedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsMinimized. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsMinimizedProperty = DependencyProperty.Register("IsMinimized", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// Gets or sets whether ribbon is opened + /// + public bool IsOpen + { + get { return (bool)this.GetValue(IsOpenProperty); } + set { this.SetValue(IsOpenProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsOpen. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// Gets or sets reduce order + /// + public string ReduceOrder + { + get { return this.groupsInnerContainer.ReduceOrder; } + set { this.groupsInnerContainer.ReduceOrder = value; } + } + + #region IsContextual + + /// + /// Gets or sets whether tab item is contextual + /// + public bool IsContextual + { + get { return (bool)this.GetValue(IsContextualProperty); } + private set { this.SetValue(IsContextualPropertyKey, value); } + } + + private static readonly DependencyPropertyKey IsContextualPropertyKey = + DependencyProperty.RegisterReadOnly("IsContextual", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// Using a DependencyProperty as the backing store for IsContextual. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsContextualProperty = IsContextualPropertyKey.DependencyProperty; + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + yield return this.groupsContainer; + } + } + + #endregion + + /// + /// Gets or sets whether tab item is selected + /// + [Bindable(true), Category("Appearance")] + public bool IsSelected + { + get + { + return (bool)this.GetValue(IsSelectedProperty); + } + set + { + this.SetValue(IsSelectedProperty, value); + } + } + + /// + /// Using a DependencyProperty as the backing store for IsSelected. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.AffectsParentMeasure, new PropertyChangedCallback(OnIsSelectedChanged))); + + /// + /// Gets ribbon tab control parent + /// + internal RibbonTabControl TabControlParent + { + get + { + return (ItemsControl.ItemsControlFromItemContainer(this) as RibbonTabControl); + } + } + + + /// + /// Gets or sets indent + /// + public double Indent + { + get { return (double)this.GetValue(IndentProperty); } + set { this.SetValue(IndentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HeaderMargin. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IndentProperty = + DependencyProperty.Register("Indent", typeof(double), typeof(RibbonTabItem), new UIPropertyMetadata((double)12.0)); + + /// + /// Gets or sets whether separator is visible + /// + public bool IsSeparatorVisible + { + get { return (bool)this.GetValue(IsSeparatorVisibleProperty); } + set { this.SetValue(IsSeparatorVisibleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsSeparatorVisible. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsSeparatorVisibleProperty = + DependencyProperty.Register("IsSeparatorVisible", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// Gets or sets ribbon contextual tab group + /// + public RibbonContextualTabGroup Group + { + get { return (RibbonContextualTabGroup)this.GetValue(GroupProperty); } + set { this.SetValue(GroupProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Group. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupProperty = + DependencyProperty.Register("Group", typeof(RibbonContextualTabGroup), typeof(RibbonTabItem), new UIPropertyMetadata(null, OnGroupChanged)); + + // handles Group property chanhged + private static void OnGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var tab = (RibbonTabItem)d; + + if (e.OldValue != null) + { + ((RibbonContextualTabGroup)e.OldValue).RemoveTabItem(tab); + } + + if (e.NewValue != null) + { + var tabGroup = (RibbonContextualTabGroup)e.NewValue; + tabGroup.AppendTabItem(tab); + tab.IsContextual = true; + } + else + { + tab.IsContextual = false; + } + } + + /// + /// Gets or sets desired width of the tab item + /// + internal double DesiredWidth + { + get { return this.desiredWidth; } + set + { + this.desiredWidth = value; + this.InvalidateMeasure(); + } + } + + /// + /// Gets or sets whether tab item has left group border + /// + public bool HasLeftGroupBorder + { + get { return (bool)this.GetValue(HasLeftGroupBorderProperty); } + set { this.SetValue(HasLeftGroupBorderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HaseLeftGroupBorder. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasLeftGroupBorderProperty = + DependencyProperty.Register("HasLeftGroupBorder", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// Gets or sets whether tab item has right group border + /// + public bool HasRightGroupBorder + { + get { return (bool)this.GetValue(HasRightGroupBorderProperty); } + set { this.SetValue(HasRightGroupBorderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HaseLeftGroupBorder. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasRightGroupBorderProperty = + DependencyProperty.Register("HasRightGroupBorder", typeof(bool), typeof(RibbonTabItem), new UIPropertyMetadata(false)); + + /// + /// get collection of ribbon groups + /// + public ObservableCollection Groups + { + get + { + if (this.groups == null) + { + this.groups = new ObservableCollection(); + this.groups.CollectionChanged += this.OnGroupsCollectionChanged; + } + return this.groups; + } + } + + // handles ribbon groups collection changes + private void OnGroupsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (this.groupsInnerContainer == null) + { + return; + } + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + for (int i = 0; i < e.NewItems.Count; i++) + { + this.groupsInnerContainer.Children.Insert(e.NewStartingIndex + i, (UIElement)e.NewItems[i]); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems.OfType()) + { + this.groupsInnerContainer.Children.Remove(item); + } + break; + + case NotifyCollectionChangedAction.Replace: + foreach (var item in e.OldItems.OfType()) + { + this.groupsInnerContainer.Children.Remove(item); + } + foreach (var item in e.NewItems.OfType()) + { + this.groupsInnerContainer.Children.Add(item); + } + break; + + case NotifyCollectionChangedAction.Reset: + this.groupsInnerContainer.Children.Clear(); + + foreach (var group in this.groups) + { + this.groupsInnerContainer.Children.Add(group); + } + break; + } + + } + + #region Header Property + + /// + /// Gets or sets header of tab item + /// + public object Header + { + get { return (object)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = + DependencyProperty.Register("Header", typeof(object), typeof(RibbonTabItem), new UIPropertyMetadata(null, OnHeaderChanged)); + + // Header changed handler + static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonTabItem tabItem = (RibbonTabItem)d; + tabItem.CoerceValue(ToolTipProperty); + } + + #endregion + + #region Focusable + + /// + /// Handles IsEnabled changes + /// + /// + /// The event data. + private static void OnFocusableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + } + + /// + /// Coerces IsEnabled + /// + /// + /// + /// + private static object CoerceFocusable(DependencyObject d, object basevalue) + { + var control = d as RibbonTabItem; + if (control != null) + { + var ribbon = control.FindParentRibbon(); + if (ribbon != null) + { + return ((bool)basevalue) + && ribbon.Focusable; + } + } + + return basevalue; + } + + // Find parent ribbon + private Ribbon FindParentRibbon() + { + var element = this.Parent; + while (element != null) + { + var ribbon = element as Ribbon; + if (ribbon != null) + { + return ribbon; + } + + element = VisualTreeHelper.GetParent(element); + } + + return null; + } + + #endregion + + #endregion + + #region Initialize + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonTabItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(typeof(RibbonTabItem))); + FocusableProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(OnFocusableChanged, CoerceFocusable)); + ToolTipProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(null, CoerceToolTip)); + VisibilityProperty.AddOwner(typeof(RibbonTabItem), new FrameworkPropertyMetadata(OnVisibilityChanged)); + StyleProperty.OverrideMetadata(typeof(RibbonTabItem), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonTabItem)); + } + + return basevalue; + } + + // Handles visibility changes + private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var item = d as RibbonTabItem; + + if (item == null) + { + return; + } + + if (item.Group != null) + { + item.Group.UpdateInnerVisiblityAndGroupBorders(); + } + + if (item.IsSelected + && (Visibility)e.NewValue == Visibility.Collapsed) + { + if (item.TabControlParent != null) + { + if (item.TabControlParent.IsMinimized) + { + item.IsSelected = false; + } + else + { + item.TabControlParent.SelectedItem = item.TabControlParent.GetFirstVisibleItem(); + } + } + } + } + + // Coerce ToolTip to ensure that tooltip displays name of the tabitem + private static object CoerceToolTip(DependencyObject d, object basevalue) + { + var tabItem = (RibbonTabItem)d; + if (basevalue == null + && tabItem.Header is string) + { + basevalue = tabItem.Header; + } + + return basevalue; + } + + /// + /// Default constructor + /// + public RibbonTabItem() + { + this.AddLogicalChild(this.groupsContainer); + this.groupsContainer.Content = this.groupsInnerContainer; + + // Force redirection of DataContext. This is needed, because we detach the container from the visual tree and attach it to a diffrent one (the popup/dropdown) when the ribbon is minimized. + this.groupsInnerContainer.SetBinding(DataContextProperty, new Binding("DataContext") + { + Source = this + }); + + ContextMenuService.Coerce(this); + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + #endregion + + #region Overrides + + /// + /// Called to remeasure a control. + /// + /// The maximum size that the method can return. + /// The size of the control, up to the maximum specified by constraint. + protected override Size MeasureOverride(Size constraint) + { + if (this.contentContainer == null) + { + return base.MeasureOverride(constraint); + } + + if (this.IsContextual && this.Group != null && this.Group.Visibility == Visibility.Collapsed) + { + return Size.Empty; + } + + this.contentContainer.Padding = new Thickness(this.Indent, this.contentContainer.Padding.Top, this.Indent, this.contentContainer.Padding.Bottom); + Size baseConstraint = base.MeasureOverride(constraint); + double totalWidth = this.contentContainer.DesiredSize.Width - this.contentContainer.Margin.Left - this.contentContainer.Margin.Right; + (this.contentContainer.Child).Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + double headerWidth = this.contentContainer.Child.DesiredSize.Width; + if (totalWidth < headerWidth + this.Indent * 2) + { + double newPaddings = Math.Max(0, (totalWidth - headerWidth) / 2); + this.contentContainer.Padding = new Thickness(newPaddings, this.contentContainer.Padding.Top, newPaddings, this.contentContainer.Padding.Bottom); + } + else + { + if (this.desiredWidth != 0) + { + // If header width is larger then tab increase tab width + if ((constraint.Width > this.desiredWidth) && (this.desiredWidth > totalWidth)) baseConstraint.Width = this.desiredWidth; + else + baseConstraint.Width = headerWidth + this.Indent * 2 + this.contentContainer.Margin.Left + this.contentContainer.Margin.Right; + } + } + + if ((this.cachedWidth != baseConstraint.Width) && (this.IsContextual) && (this.Group != null)) + { + this.cachedWidth = baseConstraint.Width; + FrameworkElement parent = (VisualTreeHelper.GetParent(this.Group) as FrameworkElement); + if (parent != null) parent.InvalidateMeasure(); + } + + return baseConstraint; + } + + /// + /// On new style applying + /// + public override void OnApplyTemplate() + { + this.contentContainer = this.GetTemplateChild("PART_ContentContainer") as Border; + } + + /// + /// Invoked when an unhandled System.Windows.UIElement.MouseLeftButtonDownrouted event is raised + /// on this element. Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + if (e.Source == this + && e.ClickCount == 2) + { + e.Handled = true; + + if (this.TabControlParent != null) + { + var canMinimize = this.TabControlParent.CanMinimize; + if (canMinimize) + { + this.TabControlParent.IsMinimized = !this.TabControlParent.IsMinimized; + } + } + } + else if (e.Source == this + || !this.IsSelected) + { + if (this.Visibility == Visibility.Visible) + { + if (this.TabControlParent != null) + { + var newItem = this.TabControlParent.ItemContainerGenerator.ItemFromContainer(this); + + if (this.TabControlParent.SelectedTabItem == newItem) + { + this.TabControlParent.IsDropDownOpen = !this.TabControlParent.IsDropDownOpen; + } + else + { + this.TabControlParent.SelectedItem = newItem; + } + + this.TabControlParent.RaiseRequestBackstageClose(); + } + else + { + this.IsSelected = true; + } + + e.Handled = true; + } + } + } + + #endregion + + #region Private methods + + // Handles IsSelected property changes + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonTabItem container = d as RibbonTabItem; + bool newValue = (bool)e.NewValue; + if (newValue) + { + if ((container.TabControlParent != null) && (container.TabControlParent.SelectedItem is RibbonTabItem) && (container.TabControlParent.SelectedItem != container)) + (container.TabControlParent.SelectedItem as RibbonTabItem).IsSelected = false; + container.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, container)); + } + else + { + container.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, container)); + } + + } + /// + /// Handles selected + /// + /// The event data + protected virtual void OnSelected(RoutedEventArgs e) + { + this.HandleIsSelectedChanged(e); + } + /// + /// handles unselected + /// + /// The event data + protected virtual void OnUnselected(RoutedEventArgs e) + { + this.HandleIsSelectedChanged(e); + } + + #endregion + + #region Event handling + + // Handles IsSelected property changes + private void HandleIsSelectedChanged(RoutedEventArgs e) + { + this.RaiseEvent(e); + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.SubscribeEvents(); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.UnSubscribeEvents(); + } + + private void SubscribeEvents() + { + // Always unsubscribe events to ensure we don't subscribe twice + this.UnSubscribeEvents(); + + if (this.groups != null) + { + this.groups.CollectionChanged += this.OnGroupsCollectionChanged; + } + } + + private void UnSubscribeEvents() + { + if (this.groups != null) + { + this.groups.CollectionChanged -= this.OnGroupsCollectionChanged; + } + } + + #endregion + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + if (this.TabControlParent != null) + { + var currentSelectedItem = this.TabControlParent.SelectedItem as RibbonTabItem; + + if (currentSelectedItem != null) + { + currentSelectedItem.IsSelected = false; + } + } + + this.IsSelected = true; + + // This way keytips for delay loaded elements work correctly. Partially fixes #244. + Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, new Action(delegate { })); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + if (this.TabControlParent != null + && this.TabControlParent.IsMinimized) + { + this.TabControlParent.IsDropDownOpen = false; + } + } + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonTabsContainer.cs b/Fluent.Ribbon/Controls/RibbonTabsContainer.cs similarity index 96% rename from Fluent/Controls/RibbonTabsContainer.cs rename to Fluent.Ribbon/Controls/RibbonTabsContainer.cs index dffdc7c39..c8ab6a116 100644 --- a/Fluent/Controls/RibbonTabsContainer.cs +++ b/Fluent.Ribbon/Controls/RibbonTabsContainer.cs @@ -1,774 +1,756 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Media; - -namespace Fluent -{ - using Fluent.Internal; - - /// - /// Represent panel with ribbon tab items. - /// It is automatically adjusting size of tabs - /// - public class RibbonTabsContainer : Panel, IScrollInfo - { - #region Fields - - - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonTabsContainer() - { - this.Focusable = false; - } - - #endregion - - #region Layout Overridings - - /// - /// Measures all of the RibbonGroupBox, and resize them appropriately - /// to fit within the available room - /// - /// The available size that this element can give to child elements. - /// The size that the groups container determines it needs during - /// layout, based on its calculations of child element sizes. - /// - [SuppressMessage("Microsoft.Maintainability", "CA1502")] - protected override Size MeasureOverride(Size availableSize) - { - if (this.InternalChildren.Count == 0) return base.MeasureOverride(availableSize); - - Size desiredSize = this.MeasureChildrenDesiredSize(availableSize); - - // Performs steps as described in "2007 MICROSOFT OFFICE FLUENT - // USER INTERFACE DESIGN GUIDELINES" - - // Step 1. Gradually remove empty space to the right of the tabs - // If all tabs already in full size, just return - if (availableSize.Width > desiredSize.Width) - { - // Hide separator lines between tabs - this.UpdateSeparators(false, false); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - // Step 2. Gradually and uniformly remove the padding from both sides - // of all the tabs until the minimum padding required for displaying - // the tab selection and hover states is reached (regular tabs) - double overflowWidth = desiredSize.Width - availableSize.Width; - double whitespace = (this.InternalChildren[0] as RibbonTabItem).Indent; - RibbonTabItem[] contextualTabs = this.InternalChildren.Cast().Where(x => (x.IsContextual) && (x.Visibility != Visibility.Collapsed) && (x.Group.Visibility != Visibility.Collapsed)).ToArray(); - double contextualTabsCount = contextualTabs.Length; - var regularTabs = this.InternalChildren.Cast().Where(x => (!x.IsContextual) && (x.Visibility != Visibility.Collapsed)); - double regularTabsCount = regularTabs.Count();//InternalChildren.Count - contextualTabsCount; - double childrenCount = contextualTabsCount + regularTabsCount; - if (overflowWidth < regularTabsCount * whitespace * 2) - { - double decreaseValue = overflowWidth / (double)regularTabsCount; - foreach (RibbonTabItem tab in regularTabs) tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - decreaseValue), tab.DesiredSize.Height));// tab.Width = Math.Max(0, tab.ActualWidth - decreaseValue); - desiredSize = this.GetChildrenDesiredSize(); - if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(false, false); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - // Step 3. Gradually and uniformly remove the padding from both sides - // of all the tabs until the minimum padding required for displaying - // the tab selection and hover states is reached (contextual tabs) - if (overflowWidth < childrenCount * whitespace * 2) - { - double regularTabsWhitespace = (double)regularTabsCount * whitespace * 2.0; - double decreaseValue = (overflowWidth - regularTabsWhitespace) / (double)contextualTabsCount; - foreach (RibbonTabItem tab in regularTabs) - { - //if (!tab.IsContextual) - { - double widthBeforeMeasure = tab.DesiredSize.Width; - tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); - overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; - } - } - foreach (RibbonTabItem tab in contextualTabs.Reverse()) - { - //if (tab.IsContextual) - { - double widthBeforeMeasure = tab.DesiredSize.Width; - tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - decreaseValue), tab.DesiredSize.Height)); - - // Contextual tabs may overreduce, so check that - overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; - if (overflowWidth < 0) break; - } - } - desiredSize = this.GetChildrenDesiredSize(); - if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, false); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - - // Step 4. Reduce the width of the tab with the longest name by - // truncating the text label. Continue reducing the width of the largest - // tab (or tabs in the case of ties) until all tabs are the same width. - // (Regular tabs) - foreach (RibbonTabItem tab in regularTabs) - { - //if (!tab.IsContextual) - { - double widthBeforeMeasure = tab.DesiredSize.Width; - tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); - overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; - } - } - foreach (RibbonTabItem tab in contextualTabs.Reverse()) - { - //if (tab.IsContextual) - { - double widthBeforeMeasure = tab.DesiredSize.Width; - tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); - - // Contextual tabs may overreduce, so check that - overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; - if (overflowWidth < 0) - { - desiredSize = this.GetChildrenDesiredSize(); - if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, false); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - } - } - - // Sort regular tabs by descending - RibbonTabItem[] sortedRegularTabItems = regularTabs - .OrderByDescending(x => x.DesiredSize.Width) - .ToArray(); - - // Find how many regular tabs we have to reduce - double reducedLength = 0; - int reduceCount = 0; - for (int i = 0; i < sortedRegularTabItems.Length - 1; i++) - { - double temp = - sortedRegularTabItems[i].DesiredSize.Width - - sortedRegularTabItems[i + 1].DesiredSize.Width; - reducedLength += temp * (i + 1); - reduceCount = i + 1; - if (reducedLength > overflowWidth) break; - } - - if (reducedLength > overflowWidth) - { - // Reduce regular tabs - double requiredWidth = sortedRegularTabItems[reduceCount].DesiredSize.Width; - if (reducedLength > overflowWidth) requiredWidth += (reducedLength - overflowWidth) / (double)reduceCount; - for (int i = 0; i < reduceCount; i++) - { - sortedRegularTabItems[i].Measure(new Size(requiredWidth, availableSize.Height)); - } - - desiredSize = this.GetChildrenDesiredSize(); - if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, true); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - - // Step 5. Reduce the width of all regular tabs equally - // down to a minimum of about three characters. - double regularTabsWidth = sortedRegularTabItems.Sum(x => x.DesiredSize.Width); - double minimumRegularTabsWidth = MinimumRegularTabWidth * sortedRegularTabItems.Length; - - if (overflowWidth < regularTabsWidth - minimumRegularTabsWidth) - { - double settedWidth = (regularTabsWidth - overflowWidth) / (double)regularTabsCount; - for (int i = 0; i < regularTabsCount; i++) - { - sortedRegularTabItems[i].Measure(new Size(settedWidth, availableSize.Height)); - } - desiredSize = this.GetChildrenDesiredSize(); - //if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, true); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - - // Step 6. Reduce the width of the tab with the longest name by - // truncating the text label. Continue reducing the width of the largest - // tab (or tabs in the case of ties) until all tabs are the same width. - // (Contextual tabs) - for (int i = 0; i < regularTabsCount; i++) - { - sortedRegularTabItems[i].Measure(new Size(MinimumRegularTabWidth, availableSize.Height)); - } - overflowWidth -= regularTabsWidth - minimumRegularTabsWidth; - - // Sort contextual tabs by descending - RibbonTabItem[] sortedContextualTabItems = contextualTabs - .OrderByDescending(x => x.DesiredSize.Width) - .ToArray(); - - // Find how many contextual tabs we have to reduce - reducedLength = 0; - reduceCount = 0; - for (int i = 0; i < sortedContextualTabItems.Length - 1; i++) - { - double temp = - sortedContextualTabItems[i].DesiredSize.Width - - sortedContextualTabItems[i + 1].DesiredSize.Width; - reducedLength += temp * (i + 1); - reduceCount = i + 1; - if (reducedLength > overflowWidth) break; - } - - if (reducedLength > overflowWidth) - { - // Reduce regular tabs - double requiredWidth = sortedContextualTabItems[reduceCount].DesiredSize.Width; - if (reducedLength > overflowWidth) requiredWidth += (reducedLength - overflowWidth) / (double)reduceCount; - for (int i = 0; i < reduceCount; i++) - { - sortedContextualTabItems[i].Measure(new Size(requiredWidth, availableSize.Height)); - } - - desiredSize = this.GetChildrenDesiredSize(); - if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, true); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - else - { - double contextualTabsWidth = sortedContextualTabItems.Sum(x => x.DesiredSize.Width); - - double settedWidth = Math.Max(MinimumRegularTabWidth, (contextualTabsWidth - overflowWidth) / (double)contextualTabsCount); - for (int i = 0; i < sortedContextualTabItems.Length; i++) - { - sortedContextualTabItems[i].Measure(new Size(settedWidth, availableSize.Height)); - } - desiredSize = this.GetChildrenDesiredSize(); - - // Add separator lines between - // tabs to assist readability - this.UpdateSeparators(true, true); - this.VerifyScrollData(availableSize.Width, desiredSize.Width); - return desiredSize; - } - } - - private Size MeasureChildrenDesiredSize(Size availableSize) - { - double width = 0; - double height = 0; - foreach (UIElement child in this.InternalChildren) - { - child.Measure(availableSize); - width += child.DesiredSize.Width; - height = Math.Max(height, child.DesiredSize.Height); - } - return new Size(width, height); - } - - private Size GetChildrenDesiredSize() - { - double width = 0; - double height = 0; - foreach (UIElement child in this.InternalChildren) - { - width += child.DesiredSize.Width; - height = Math.Max(height, child.DesiredSize.Height); - } - return new Size(width, height); - } - - /// - /// Positions child elements and determines - /// a size for the control - /// - /// The final area within the parent - /// that this element should use to arrange - /// itself and its children - /// The actual size used - protected override Size ArrangeOverride(Size finalSize) - { - var finalRect = new Rect(finalSize) - { - X = -this.HorizontalOffset - }; - - var orderedChildren = this.InternalChildren.OfType() - .OrderBy(x => x.Group != null); - - foreach (var item in orderedChildren) - { - finalRect.Width = item.DesiredSize.Width; - finalRect.Height = Math.Max(finalSize.Height, item.DesiredSize.Height); - item.Arrange(finalRect); - finalRect.X += item.DesiredSize.Width; - } - - var ribbonTabItemsWithGroups = this.InternalChildren.OfType() - .Where(item => item.Group != null); - - var ribbonTitleBar = ribbonTabItemsWithGroups.Select(ribbonTabItemsWithGroup => ribbonTabItemsWithGroup.Group.Parent) - .OfType() - .FirstOrDefault(); - - if (ribbonTitleBar != null) - { - ribbonTitleBar.InvalidateMeasure(); - } - - return finalSize; - } - - /// - /// Updates separator visibility - /// - /// If this parameter true, regular tabs will have separators - /// If this parameter true, contextual tabs will have separators - private void UpdateSeparators(bool regularTabs, bool contextualTabs) - { - foreach (RibbonTabItem tab in this.Children) - { - if (tab.IsContextual) - { - if (tab.IsSeparatorVisible != contextualTabs) tab.IsSeparatorVisible = contextualTabs; - } - else if (tab.IsSeparatorVisible != regularTabs) - { - tab.IsSeparatorVisible = regularTabs; - } - } - } - - #endregion - - #region IScrollInfo Members - - /// - /// Gets or sets a System.Windows.Controls.ScrollViewer element that controls scrolling behavior. - /// - public ScrollViewer ScrollOwner - { - get { return this.ScrollData.ScrollOwner; } - set { this.ScrollData.ScrollOwner = value; } - } - - /// - /// Sets the amount of horizontal offset. - /// - /// The degree to which content is horizontally offset from the containing viewport. - public void SetHorizontalOffset(double offset) - { - double newValue = CoerceOffset(ValidateInputOffset(offset, "HorizontalOffset"), this.scrollData.ExtentWidth, this.scrollData.ViewportWidth); - if (DoubleUtil.AreClose(this.ScrollData.OffsetX, newValue) == false) - { - this.scrollData.OffsetX = newValue; - this.InvalidateArrange(); - } - } - - /// - /// Gets the horizontal size of the extent. - /// - public double ExtentWidth - { - get { return this.ScrollData.ExtentWidth; } - } - - /// - /// Gets the horizontal offset of the scrolled content. - /// - public double HorizontalOffset - { - get { return this.ScrollData.OffsetX; } - } - - /// - /// Gets the horizontal size of the viewport for this content. - /// - public double ViewportWidth - { - get { return this.ScrollData.ViewportWidth; } - } - - /// - /// Scrolls left within content by one logical unit. - /// - public void LineLeft() - { - this.SetHorizontalOffset(this.HorizontalOffset - 16.0); - } - - /// - /// Scrolls right within content by one logical unit. - /// - public void LineRight() - { - this.SetHorizontalOffset(this.HorizontalOffset + 16.0); - } - - /// - /// Forces content to scroll until the coordinate space of a System.Windows.Media.Visual object is visible. - /// This is optimized for horizontal scrolling only - /// - /// A System.Windows.Media.Visual that becomes visible. - /// A bounding rectangle that identifies the coordinate space to make visible. - /// A System.Windows.Rect that is visible. - public Rect MakeVisible(Visual visual, Rect rectangle) - { - // We can only work on visuals that are us or children. - // An empty rect has no size or position. We can't meaningfully use it. - if (rectangle.IsEmpty - || visual == null - || visual == (Visual)this - || !this.IsAncestorOf(visual)) - { - return Rect.Empty; - } - - // Compute the child's rect relative to (0,0) in our coordinate space. - GeneralTransform childTransform = visual.TransformToAncestor(this); - - rectangle = childTransform.TransformBounds(rectangle); - - // Initialize the viewport - Rect viewport = new Rect(this.HorizontalOffset, rectangle.Top, this.ViewportWidth, rectangle.Height); - rectangle.X += viewport.X; - - // Compute the offsets required to minimally scroll the child maximally into view. - double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right); - - // We have computed the scrolling offsets; scroll to them. - this.SetHorizontalOffset(minX); - - // Compute the visible rectangle of the child relative to the viewport. - viewport.X = minX; - rectangle.Intersect(viewport); - - rectangle.X -= viewport.X; - - // Return the rectangle - return rectangle; - } - - static double ComputeScrollOffsetWithMinimalScroll( - double topView, - double bottomView, - double topChild, - double bottomChild) - { - // # CHILD POSITION CHILD SIZE SCROLL REMEDY - // 1 Above viewport <= viewport Down Align top edge of child & viewport - // 2 Above viewport > viewport Down Align bottom edge of child & viewport - // 3 Below viewport <= viewport Up Align bottom edge of child & viewport - // 4 Below viewport > viewport Up Align top edge of child & viewport - // 5 Entirely within viewport NA No scroll. - // 6 Spanning viewport NA No scroll. - // - // Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom - // "Below viewport" = childTop below viewportTop, childBottom below viewportBottom - // These child thus may overlap with the viewport, but will scroll the same direction - /*bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView); - bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);*/ - bool fAbove = (topChild < topView) && (bottomChild < bottomView); - bool fBelow = (bottomChild > bottomView) && (topChild > topView); - bool fLarger = (bottomChild - topChild) > (bottomView - topView); - - // Handle Cases: 1 & 4 above - if ((fAbove && !fLarger) - || (fBelow && fLarger)) - { - return topChild; - } - - // Handle Cases: 2 & 3 above - else if (fAbove || fBelow) - { - return bottomChild - (bottomView - topView); - } - - // Handle cases: 5 & 6 above. - return topView; - } - - /// - /// Not implemented - /// - public void MouseWheelDown() - { - } - /// - /// Not implemented - /// - public void MouseWheelLeft() - { - } - /// - /// Not implemented - /// - public void MouseWheelRight() - { - } - /// - /// Not implemented - /// - public void MouseWheelUp() - { - } - /// - /// Not implemented - /// - public void LineDown() - { - } - /// - /// Not implemented - /// - public void LineUp() - { - } - /// - /// Not implemented - /// - public void PageDown() - { - } - /// - /// Not implemented - /// - public void PageLeft() - { - } - /// - /// Not implemented - /// - public void PageRight() - { - } - /// - /// Not implemented - /// - public void PageUp() - { - } - /// - /// Not implemented - /// - /// - public void SetVerticalOffset(double offset) - { - } - /// - /// Gets or sets a value that indicates whether scrolling on the vertical axis is possible. - /// - public bool CanVerticallyScroll - { - get { return false; } - set { } - } - /// - /// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible. - /// - public bool CanHorizontallyScroll - { - get { return true; } - set { } - } - /// - /// Not implemented - /// - public double ExtentHeight - { - get { return 0.0; } - }/// - /// Not implemented - /// - - public double VerticalOffset - { - get { return 0.0; } - } - /// - /// Not implemented - /// - public double ViewportHeight - { - get { return 0.0; } - } - - // Gets scroll data info - private ScrollData ScrollData - { - get - { - return this.scrollData ?? (this.scrollData = new ScrollData()); - } - } - - // Scroll data info - private ScrollData scrollData; - private const double MinimumRegularTabWidth = 30D; - - // Validates input offset - static double ValidateInputOffset(double offset, string parameterName) - { - if (double.IsNaN(offset)) - { - throw new ArgumentOutOfRangeException(parameterName); - } - - return Math.Max(0.0, offset); - } - - // Verifies scrolling data using the passed viewport and extent as newly computed values. - // Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize] - // If extent, viewport, or the newly coerced offsets are different than the existing offset, - // cachces are updated and InvalidateScrollInfo() is called. - private void VerifyScrollData(double viewportWidth, double extentWidth) - { - bool isValid = true; - - if (double.IsInfinity(viewportWidth)) - { - viewportWidth = extentWidth; - } - - double offsetX = CoerceOffset(this.ScrollData.OffsetX, extentWidth, viewportWidth); - - isValid &= DoubleUtil.AreClose(viewportWidth, this.ScrollData.ViewportWidth); - isValid &= DoubleUtil.AreClose(extentWidth, this.ScrollData.ExtentWidth); - isValid &= DoubleUtil.AreClose(this.ScrollData.OffsetX, offsetX); - - this.ScrollData.ViewportWidth = viewportWidth; - - // newExtentWidth is neccessary to fix 20762 (Tab scroll button appears randomly when resizing) - // To fix 20762 we are manipulating the extentWidth by checking if all regular (non contextual) tabs are at their minimum width. - // When they are all at their minimum width we have to force the extentWidth to be greater than the viewportWidth. - // When there are no regular tabs, we MUST NOT apply this fix - var newExtentWidth = Math.Max(viewportWidth, extentWidth); - - var visibleRegularTabs = this.InternalChildren.Cast() - .Where(item => item.IsContextual == false && item.Visibility != Visibility.Collapsed) - .ToArray(); - - if (visibleRegularTabs.Any() - && visibleRegularTabs.All(item => DoubleUtil.AreClose(item.DesiredSize.Width, MinimumRegularTabWidth))) - { - if (DoubleUtil.AreClose(newExtentWidth, viewportWidth)) - { - newExtentWidth = newExtentWidth + 1; - } - - this.ScrollData.ExtentWidth = newExtentWidth; - } - else - { - this.ScrollData.ExtentWidth = this.ScrollData.ViewportWidth; - } - - this.ScrollData.OffsetX = offsetX; - - if (!isValid) - { - if (this.ScrollOwner != null) - { - this.ScrollOwner.InvalidateScrollInfo(); - } - } - } - - // Returns an offset coerced into the [0, Extent - Viewport] range. - static double CoerceOffset(double offset, double extent, double viewport) - { - if (offset > extent - viewport) - { - offset = extent - viewport; - } - - if (offset < 0) - { - offset = 0; - } - - return offset; - } - - #endregion - } - - #region ScrollData - - /// - /// Helper class to hold scrolling data. - /// This class exists to reduce working set when SCP is delegating to another implementation of ISI. - /// Standard "extra pointer always for less data sometimes" cache savings model: - /// - internal class ScrollData - { - /// - /// Scroll viewer - /// - internal ScrollViewer ScrollOwner; - - /// - /// Scroll offset - /// - internal double OffsetX; - - /// - /// ViewportSize is computed from our FinalSize, but may be in different units. - /// - internal double ViewportWidth; - - /// - /// Extent is the total size of our content. - /// - internal double ExtentWidth; - } - - #endregion ScrollData +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; + +namespace Fluent +{ + using Fluent.Internal; + + /// + /// Represent panel with ribbon tab items. + /// It is automatically adjusting size of tabs + /// + public class RibbonTabsContainer : Panel, IScrollInfo + { + /// + /// Default constructor + /// + public RibbonTabsContainer() + { + this.Focusable = false; + } + + #region Layout Overridings + + /// + /// Measures all of the RibbonGroupBox, and resize them appropriately + /// to fit within the available room + /// + /// The available size that this element can give to child elements. + /// The size that the groups container determines it needs during + /// layout, based on its calculations of child element sizes. + /// + [SuppressMessage("Microsoft.Maintainability", "CA1502")] + protected override Size MeasureOverride(Size availableSize) + { + if (this.InternalChildren.Count == 0) return base.MeasureOverride(availableSize); + + Size desiredSize = this.MeasureChildrenDesiredSize(availableSize); + + // Performs steps as described in "2007 MICROSOFT OFFICE FLUENT + // USER INTERFACE DESIGN GUIDELINES" + + // Step 1. Gradually remove empty space to the right of the tabs + // If all tabs already in full size, just return + if (availableSize.Width > desiredSize.Width) + { + // Hide separator lines between tabs + this.UpdateSeparators(false, false); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + // Step 2. Gradually and uniformly remove the padding from both sides + // of all the tabs until the minimum padding required for displaying + // the tab selection and hover states is reached (regular tabs) + double overflowWidth = desiredSize.Width - availableSize.Width; + double whitespace = (this.InternalChildren[0] as RibbonTabItem).Indent; + RibbonTabItem[] contextualTabs = this.InternalChildren.Cast().Where(x => (x.IsContextual) && (x.Visibility != Visibility.Collapsed) && (x.Group.Visibility != Visibility.Collapsed)).ToArray(); + double contextualTabsCount = contextualTabs.Length; + var regularTabs = this.InternalChildren.Cast().Where(x => (!x.IsContextual) && (x.Visibility != Visibility.Collapsed)); + double regularTabsCount = regularTabs.Count();//InternalChildren.Count - contextualTabsCount; + double childrenCount = contextualTabsCount + regularTabsCount; + if (overflowWidth < regularTabsCount * whitespace * 2) + { + double decreaseValue = overflowWidth / (double)regularTabsCount; + foreach (RibbonTabItem tab in regularTabs) tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - decreaseValue), tab.DesiredSize.Height));// tab.Width = Math.Max(0, tab.ActualWidth - decreaseValue); + desiredSize = this.GetChildrenDesiredSize(); + if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(false, false); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + // Step 3. Gradually and uniformly remove the padding from both sides + // of all the tabs until the minimum padding required for displaying + // the tab selection and hover states is reached (contextual tabs) + if (overflowWidth < childrenCount * whitespace * 2) + { + double regularTabsWhitespace = (double)regularTabsCount * whitespace * 2.0; + double decreaseValue = (overflowWidth - regularTabsWhitespace) / (double)contextualTabsCount; + foreach (RibbonTabItem tab in regularTabs) + { + //if (!tab.IsContextual) + { + double widthBeforeMeasure = tab.DesiredSize.Width; + tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); + overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; + } + } + foreach (RibbonTabItem tab in contextualTabs.Reverse()) + { + //if (tab.IsContextual) + { + double widthBeforeMeasure = tab.DesiredSize.Width; + tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - decreaseValue), tab.DesiredSize.Height)); + + // Contextual tabs may overreduce, so check that + overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; + if (overflowWidth < 0) break; + } + } + desiredSize = this.GetChildrenDesiredSize(); + if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, false); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + + // Step 4. Reduce the width of the tab with the longest name by + // truncating the text label. Continue reducing the width of the largest + // tab (or tabs in the case of ties) until all tabs are the same width. + // (Regular tabs) + foreach (RibbonTabItem tab in regularTabs) + { + //if (!tab.IsContextual) + { + double widthBeforeMeasure = tab.DesiredSize.Width; + tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); + overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; + } + } + foreach (RibbonTabItem tab in contextualTabs.Reverse()) + { + //if (tab.IsContextual) + { + double widthBeforeMeasure = tab.DesiredSize.Width; + tab.Measure(new Size(Math.Max(0, tab.DesiredSize.Width - whitespace * 2.0), tab.DesiredSize.Height)); + + // Contextual tabs may overreduce, so check that + overflowWidth -= widthBeforeMeasure - tab.DesiredSize.Width; + if (overflowWidth < 0) + { + desiredSize = this.GetChildrenDesiredSize(); + if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, false); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + } + } + + // Sort regular tabs by descending + RibbonTabItem[] sortedRegularTabItems = regularTabs + .OrderByDescending(x => x.DesiredSize.Width) + .ToArray(); + + // Find how many regular tabs we have to reduce + double reducedLength = 0; + int reduceCount = 0; + for (int i = 0; i < sortedRegularTabItems.Length - 1; i++) + { + double temp = + sortedRegularTabItems[i].DesiredSize.Width - + sortedRegularTabItems[i + 1].DesiredSize.Width; + reducedLength += temp * (i + 1); + reduceCount = i + 1; + if (reducedLength > overflowWidth) break; + } + + if (reducedLength > overflowWidth) + { + // Reduce regular tabs + double requiredWidth = sortedRegularTabItems[reduceCount].DesiredSize.Width; + if (reducedLength > overflowWidth) requiredWidth += (reducedLength - overflowWidth) / (double)reduceCount; + for (int i = 0; i < reduceCount; i++) + { + sortedRegularTabItems[i].Measure(new Size(requiredWidth, availableSize.Height)); + } + + desiredSize = this.GetChildrenDesiredSize(); + if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, true); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + + // Step 5. Reduce the width of all regular tabs equally + // down to a minimum of about three characters. + double regularTabsWidth = sortedRegularTabItems.Sum(x => x.DesiredSize.Width); + double minimumRegularTabsWidth = MinimumRegularTabWidth * sortedRegularTabItems.Length; + + if (overflowWidth < regularTabsWidth - minimumRegularTabsWidth) + { + double settedWidth = (regularTabsWidth - overflowWidth) / (double)regularTabsCount; + for (int i = 0; i < regularTabsCount; i++) + { + sortedRegularTabItems[i].Measure(new Size(settedWidth, availableSize.Height)); + } + desiredSize = this.GetChildrenDesiredSize(); + //if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, true); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + + // Step 6. Reduce the width of the tab with the longest name by + // truncating the text label. Continue reducing the width of the largest + // tab (or tabs in the case of ties) until all tabs are the same width. + // (Contextual tabs) + for (int i = 0; i < regularTabsCount; i++) + { + sortedRegularTabItems[i].Measure(new Size(MinimumRegularTabWidth, availableSize.Height)); + } + overflowWidth -= regularTabsWidth - minimumRegularTabsWidth; + + // Sort contextual tabs by descending + RibbonTabItem[] sortedContextualTabItems = contextualTabs + .OrderByDescending(x => x.DesiredSize.Width) + .ToArray(); + + // Find how many contextual tabs we have to reduce + reducedLength = 0; + reduceCount = 0; + for (int i = 0; i < sortedContextualTabItems.Length - 1; i++) + { + double temp = + sortedContextualTabItems[i].DesiredSize.Width - + sortedContextualTabItems[i + 1].DesiredSize.Width; + reducedLength += temp * (i + 1); + reduceCount = i + 1; + if (reducedLength > overflowWidth) break; + } + + if (reducedLength > overflowWidth) + { + // Reduce regular tabs + double requiredWidth = sortedContextualTabItems[reduceCount].DesiredSize.Width; + if (reducedLength > overflowWidth) requiredWidth += (reducedLength - overflowWidth) / (double)reduceCount; + for (int i = 0; i < reduceCount; i++) + { + sortedContextualTabItems[i].Measure(new Size(requiredWidth, availableSize.Height)); + } + + desiredSize = this.GetChildrenDesiredSize(); + if (desiredSize.Width > availableSize.Width) desiredSize.Width = availableSize.Width; + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, true); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + else + { + double contextualTabsWidth = sortedContextualTabItems.Sum(x => x.DesiredSize.Width); + + double settedWidth = Math.Max(MinimumRegularTabWidth, (contextualTabsWidth - overflowWidth) / (double)contextualTabsCount); + for (int i = 0; i < sortedContextualTabItems.Length; i++) + { + sortedContextualTabItems[i].Measure(new Size(settedWidth, availableSize.Height)); + } + desiredSize = this.GetChildrenDesiredSize(); + + // Add separator lines between + // tabs to assist readability + this.UpdateSeparators(true, true); + this.VerifyScrollData(availableSize.Width, desiredSize.Width); + return desiredSize; + } + } + + private Size MeasureChildrenDesiredSize(Size availableSize) + { + double width = 0; + double height = 0; + foreach (UIElement child in this.InternalChildren) + { + child.Measure(availableSize); + width += child.DesiredSize.Width; + height = Math.Max(height, child.DesiredSize.Height); + } + return new Size(width, height); + } + + private Size GetChildrenDesiredSize() + { + double width = 0; + double height = 0; + foreach (UIElement child in this.InternalChildren) + { + width += child.DesiredSize.Width; + height = Math.Max(height, child.DesiredSize.Height); + } + return new Size(width, height); + } + + /// + /// Positions child elements and determines + /// a size for the control + /// + /// The final area within the parent + /// that this element should use to arrange + /// itself and its children + /// The actual size used + protected override Size ArrangeOverride(Size finalSize) + { + var finalRect = new Rect(finalSize) + { + X = -this.HorizontalOffset + }; + + var orderedChildren = this.InternalChildren.OfType() + .OrderBy(x => x.Group != null); + + foreach (var item in orderedChildren) + { + finalRect.Width = item.DesiredSize.Width; + finalRect.Height = Math.Max(finalSize.Height, item.DesiredSize.Height); + item.Arrange(finalRect); + finalRect.X += item.DesiredSize.Width; + } + + var ribbonTabItemsWithGroups = this.InternalChildren.OfType() + .Where(item => item.Group != null); + + var ribbonTitleBar = ribbonTabItemsWithGroups.Select(ribbonTabItemsWithGroup => ribbonTabItemsWithGroup.Group.Parent) + .OfType() + .FirstOrDefault(); + + if (ribbonTitleBar != null) + { + ribbonTitleBar.InvalidateMeasure(); + } + + return finalSize; + } + + /// + /// Updates separator visibility + /// + /// If this parameter true, regular tabs will have separators + /// If this parameter true, contextual tabs will have separators + private void UpdateSeparators(bool regularTabs, bool contextualTabs) + { + foreach (RibbonTabItem tab in this.Children) + { + if (tab.IsContextual) + { + if (tab.IsSeparatorVisible != contextualTabs) tab.IsSeparatorVisible = contextualTabs; + } + else if (tab.IsSeparatorVisible != regularTabs) + { + tab.IsSeparatorVisible = regularTabs; + } + } + } + + #endregion + + #region IScrollInfo Members + + /// + /// Gets or sets a System.Windows.Controls.ScrollViewer element that controls scrolling behavior. + /// + public ScrollViewer ScrollOwner + { + get { return this.ScrollData.ScrollOwner; } + set { this.ScrollData.ScrollOwner = value; } + } + + /// + /// Sets the amount of horizontal offset. + /// + /// The degree to which content is horizontally offset from the containing viewport. + public void SetHorizontalOffset(double offset) + { + double newValue = CoerceOffset(ValidateInputOffset(offset, "HorizontalOffset"), this.scrollData.ExtentWidth, this.scrollData.ViewportWidth); + if (DoubleUtil.AreClose(this.ScrollData.OffsetX, newValue) == false) + { + this.scrollData.OffsetX = newValue; + this.InvalidateArrange(); + } + } + + /// + /// Gets the horizontal size of the extent. + /// + public double ExtentWidth + { + get { return this.ScrollData.ExtentWidth; } + } + + /// + /// Gets the horizontal offset of the scrolled content. + /// + public double HorizontalOffset + { + get { return this.ScrollData.OffsetX; } + } + + /// + /// Gets the horizontal size of the viewport for this content. + /// + public double ViewportWidth + { + get { return this.ScrollData.ViewportWidth; } + } + + /// + /// Scrolls left within content by one logical unit. + /// + public void LineLeft() + { + this.SetHorizontalOffset(this.HorizontalOffset - 16.0); + } + + /// + /// Scrolls right within content by one logical unit. + /// + public void LineRight() + { + this.SetHorizontalOffset(this.HorizontalOffset + 16.0); + } + + /// + /// Forces content to scroll until the coordinate space of a System.Windows.Media.Visual object is visible. + /// This is optimized for horizontal scrolling only + /// + /// A System.Windows.Media.Visual that becomes visible. + /// A bounding rectangle that identifies the coordinate space to make visible. + /// A System.Windows.Rect that is visible. + public Rect MakeVisible(Visual visual, Rect rectangle) + { + // We can only work on visuals that are us or children. + // An empty rect has no size or position. We can't meaningfully use it. + if (rectangle.IsEmpty + || visual == null + || visual == (Visual)this + || !this.IsAncestorOf(visual)) + { + return Rect.Empty; + } + + // Compute the child's rect relative to (0,0) in our coordinate space. + GeneralTransform childTransform = visual.TransformToAncestor(this); + + rectangle = childTransform.TransformBounds(rectangle); + + // Initialize the viewport + Rect viewport = new Rect(this.HorizontalOffset, rectangle.Top, this.ViewportWidth, rectangle.Height); + rectangle.X += viewport.X; + + // Compute the offsets required to minimally scroll the child maximally into view. + double minX = ComputeScrollOffsetWithMinimalScroll(viewport.Left, viewport.Right, rectangle.Left, rectangle.Right); + + // We have computed the scrolling offsets; scroll to them. + this.SetHorizontalOffset(minX); + + // Compute the visible rectangle of the child relative to the viewport. + viewport.X = minX; + rectangle.Intersect(viewport); + + rectangle.X -= viewport.X; + + // Return the rectangle + return rectangle; + } + + static double ComputeScrollOffsetWithMinimalScroll( + double topView, + double bottomView, + double topChild, + double bottomChild) + { + // # CHILD POSITION CHILD SIZE SCROLL REMEDY + // 1 Above viewport <= viewport Down Align top edge of child & viewport + // 2 Above viewport > viewport Down Align bottom edge of child & viewport + // 3 Below viewport <= viewport Up Align bottom edge of child & viewport + // 4 Below viewport > viewport Up Align top edge of child & viewport + // 5 Entirely within viewport NA No scroll. + // 6 Spanning viewport NA No scroll. + // + // Note: "Above viewport" = childTop above viewportTop, childBottom above viewportBottom + // "Below viewport" = childTop below viewportTop, childBottom below viewportBottom + // These child thus may overlap with the viewport, but will scroll the same direction + /*bool fAbove = DoubleUtil.LessThan(topChild, topView) && DoubleUtil.LessThan(bottomChild, bottomView); + bool fBelow = DoubleUtil.GreaterThan(bottomChild, bottomView) && DoubleUtil.GreaterThan(topChild, topView);*/ + bool fAbove = (topChild < topView) && (bottomChild < bottomView); + bool fBelow = (bottomChild > bottomView) && (topChild > topView); + bool fLarger = (bottomChild - topChild) > (bottomView - topView); + + // Handle Cases: 1 & 4 above + if ((fAbove && !fLarger) + || (fBelow && fLarger)) + { + return topChild; + } + + // Handle Cases: 2 & 3 above + else if (fAbove || fBelow) + { + return bottomChild - (bottomView - topView); + } + + // Handle cases: 5 & 6 above. + return topView; + } + + /// + /// Not implemented + /// + public void MouseWheelDown() + { + } + /// + /// Not implemented + /// + public void MouseWheelLeft() + { + } + /// + /// Not implemented + /// + public void MouseWheelRight() + { + } + /// + /// Not implemented + /// + public void MouseWheelUp() + { + } + /// + /// Not implemented + /// + public void LineDown() + { + } + /// + /// Not implemented + /// + public void LineUp() + { + } + /// + /// Not implemented + /// + public void PageDown() + { + } + /// + /// Not implemented + /// + public void PageLeft() + { + } + /// + /// Not implemented + /// + public void PageRight() + { + } + /// + /// Not implemented + /// + public void PageUp() + { + } + /// + /// Not implemented + /// + /// + public void SetVerticalOffset(double offset) + { + } + /// + /// Gets or sets a value that indicates whether scrolling on the vertical axis is possible. + /// + public bool CanVerticallyScroll + { + get { return false; } + set { } + } + /// + /// Gets or sets a value that indicates whether scrolling on the horizontal axis is possible. + /// + public bool CanHorizontallyScroll + { + get { return true; } + set { } + } + /// + /// Not implemented + /// + public double ExtentHeight + { + get { return 0.0; } + }/// + /// Not implemented + /// + + public double VerticalOffset + { + get { return 0.0; } + } + /// + /// Not implemented + /// + public double ViewportHeight + { + get { return 0.0; } + } + + // Gets scroll data info + private ScrollData ScrollData + { + get + { + return this.scrollData ?? (this.scrollData = new ScrollData()); + } + } + + // Scroll data info + private ScrollData scrollData; + private const double MinimumRegularTabWidth = 30D; + + // Validates input offset + static double ValidateInputOffset(double offset, string parameterName) + { + if (double.IsNaN(offset)) + { + throw new ArgumentOutOfRangeException(parameterName); + } + + return Math.Max(0.0, offset); + } + + // Verifies scrolling data using the passed viewport and extent as newly computed values. + // Checks the X/Y offset and coerces them into the range [0, Extent - ViewportSize] + // If extent, viewport, or the newly coerced offsets are different than the existing offset, + // cachces are updated and InvalidateScrollInfo() is called. + private void VerifyScrollData(double viewportWidth, double extentWidth) + { + bool isValid = true; + + if (double.IsInfinity(viewportWidth)) + { + viewportWidth = extentWidth; + } + + double offsetX = CoerceOffset(this.ScrollData.OffsetX, extentWidth, viewportWidth); + + isValid &= DoubleUtil.AreClose(viewportWidth, this.ScrollData.ViewportWidth); + isValid &= DoubleUtil.AreClose(extentWidth, this.ScrollData.ExtentWidth); + isValid &= DoubleUtil.AreClose(this.ScrollData.OffsetX, offsetX); + + this.ScrollData.ViewportWidth = viewportWidth; + + // newExtentWidth is neccessary to fix 20762 (Tab scroll button appears randomly when resizing) + // To fix 20762 we are manipulating the extentWidth by checking if all regular (non contextual) tabs are at their minimum width. + // When they are all at their minimum width we have to force the extentWidth to be greater than the viewportWidth. + // When there are no regular tabs, we MUST NOT apply this fix + var newExtentWidth = Math.Max(viewportWidth, extentWidth); + + var visibleRegularTabs = this.InternalChildren.Cast() + .Where(item => item.IsContextual == false && item.Visibility != Visibility.Collapsed) + .ToArray(); + + if (visibleRegularTabs.Any() + && visibleRegularTabs.All(item => DoubleUtil.AreClose(item.DesiredSize.Width, MinimumRegularTabWidth))) + { + if (DoubleUtil.AreClose(newExtentWidth, viewportWidth)) + { + newExtentWidth = newExtentWidth + 1; + } + + this.ScrollData.ExtentWidth = newExtentWidth; + } + else + { + this.ScrollData.ExtentWidth = this.ScrollData.ViewportWidth; + } + + this.ScrollData.OffsetX = offsetX; + + if (!isValid) + { + if (this.ScrollOwner != null) + { + this.ScrollOwner.InvalidateScrollInfo(); + } + } + } + + // Returns an offset coerced into the [0, Extent - Viewport] range. + static double CoerceOffset(double offset, double extent, double viewport) + { + if (offset > extent - viewport) + { + offset = extent - viewport; + } + + if (offset < 0) + { + offset = 0; + } + + return offset; + } + + #endregion + } + + #region ScrollData + + /// + /// Helper class to hold scrolling data. + /// This class exists to reduce working set when SCP is delegating to another implementation of ISI. + /// Standard "extra pointer always for less data sometimes" cache savings model: + /// + internal class ScrollData + { + /// + /// Scroll viewer + /// + internal ScrollViewer ScrollOwner; + + /// + /// Scroll offset + /// + internal double OffsetX; + + /// + /// ViewportSize is computed from our FinalSize, but may be in different units. + /// + internal double ViewportWidth; + + /// + /// Extent is the total size of our content. + /// + internal double ExtentWidth; + } + + #endregion ScrollData } \ No newline at end of file diff --git a/Fluent/Controls/RibbonTitleBar.cs b/Fluent.Ribbon/Controls/RibbonTitleBar.cs similarity index 96% rename from Fluent/Controls/RibbonTitleBar.cs rename to Fluent.Ribbon/Controls/RibbonTitleBar.cs index 6d9e3e023..fbf38a823 100644 --- a/Fluent/Controls/RibbonTitleBar.cs +++ b/Fluent.Ribbon/Controls/RibbonTitleBar.cs @@ -1,426 +1,417 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using Fluent.Internal; - -namespace Fluent -{ - /// - /// Represents title bar - /// - [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonContextualTabGroup))] - [TemplatePart(Name = "PART_QuickAccessToolbarHolder", Type = typeof(FrameworkElement))] - [TemplatePart(Name = "PART_HeaderHolder", Type = typeof(FrameworkElement))] - [TemplatePart(Name = "PART_ItemsContainer", Type = typeof(Panel))] - public class RibbonTitleBar : HeaderedItemsControl - { - #region Fields - - // Quick access toolbar holder - private FrameworkElement quickAccessToolbarHolder; - // Header holder - private FrameworkElement headerHolder; - // Items container - private Panel itemsContainer; - // Quick access toolbar rect - private Rect quickAccessToolbarRect; - // Header rect - private Rect headerRect; - // Items rect - private Rect itemsRect; - - #endregion - - #region Properties - - /// - /// Gets or sets quick access toolbar - /// - public UIElement QuickAccessToolBar - { - get { return (UIElement)this.GetValue(QuickAccessToolBarProperty); } - set { this.SetValue(QuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for QuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty QuickAccessToolBarProperty = - DependencyProperty.Register("QuickAccessToolBar", typeof(UIElement), typeof(RibbonTitleBar), new UIPropertyMetadata(null, OnQuickAccessToolbarChanged)); - - // Handles QuickAccessToolBar property chages - private static void OnQuickAccessToolbarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var titleBar = (RibbonTitleBar)d; - titleBar.InvalidateMeasure(); - } - - /// - /// Gets or sets header alignment - /// - public HorizontalAlignment HeaderAlignment - { - get { return (HorizontalAlignment)this.GetValue(HeaderAlignmentProperty); } - set { this.SetValue(HeaderAlignmentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HeaderAlignment. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderAlignmentProperty = - DependencyProperty.Register("HeaderAlignment", typeof(HorizontalAlignment), typeof(RibbonTitleBar), new UIPropertyMetadata(HorizontalAlignment.Center)); - - /// - /// Defines whether title bar is collapsed - /// - public bool IsCollapsed - { - get { return (bool)this.GetValue(IsCollapsedProperty); } - set { this.SetValue(IsCollapsedProperty, value); } - } - - /// - /// DependencyProperty for - /// - public static readonly DependencyProperty IsCollapsedProperty = - DependencyProperty.Register("IsCollapsed", typeof(bool), typeof(RibbonTitleBar), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); - - private bool isAtLeastOneRequiredControlPresent; - - /// - /// Using a DependencyProperty as the backing store for HideContextTabs. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HideContextTabsProperty = - DependencyProperty.Register("HideContextTabs", typeof(bool), typeof(RibbonTitleBar), new PropertyMetadata(false)); - - /// - /// Gets or sets whether context tabs are hidden. - /// - public bool HideContextTabs - { - get { return (bool)this.GetValue(HideContextTabsProperty); } - set { this.SetValue(HideContextTabsProperty, value); } - } - - #endregion - - #region Initialize - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonTitleBar() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonTitleBar), new FrameworkPropertyMetadata(typeof(RibbonTitleBar))); - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { - return new RibbonContextualTabGroup(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// true if the item is (or is eligible to be) its own container; otherwise, false. - protected override bool IsItemItsOwnContainerOverride(object item) - { - return item is RibbonContextualTabGroup; - } - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes - /// call System.Windows.FrameworkElement.ApplyTemplate(). - /// - public override void OnApplyTemplate() - { - this.quickAccessToolbarHolder = this.GetTemplateChild("PART_QuickAccessToolbarHolder") as FrameworkElement; - this.headerHolder = this.GetTemplateChild("PART_HeaderHolder") as FrameworkElement; - this.itemsContainer = this.GetTemplateChild("PART_ItemsContainer") as Panel; - - this.isAtLeastOneRequiredControlPresent = this.quickAccessToolbarHolder != null - || this.headerHolder != null - || this.itemsContainer != null; - } - - /// - /// Called to remeasure a control. - /// - /// The maximum size that the method can return. - /// The size of the control, up to the maximum specified by constraint. - protected override Size MeasureOverride(Size constraint) - { - if (this.isAtLeastOneRequiredControlPresent == false) - { - return base.MeasureOverride(constraint); - } - - if (this.IsCollapsed) - { - return base.MeasureOverride(constraint); - } - - var resultSize = constraint; - - if (double.IsPositiveInfinity(resultSize.Width) - || double.IsPositiveInfinity(resultSize.Height)) - { - resultSize = base.MeasureOverride(resultSize); - } - - this.Update(resultSize); - - this.itemsContainer.Measure(this.itemsRect.Size); - this.headerHolder.Measure(this.headerRect.Size); - this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); - - var maxHeight = Math.Max(Math.Max(this.itemsRect.Height, this.headerRect.Height), this.quickAccessToolbarRect.Height); - var width = this.itemsRect.Width + this.headerRect.Width + this.quickAccessToolbarRect.Width; - - return new Size(width, maxHeight); - } - - /// - /// Called to arrange and size the content of a System.Windows.Controls.Control object. - /// - /// The computed size that is used to arrange the content. - /// The size of the control. - protected override Size ArrangeOverride(Size arrangeBounds) - { - if (this.isAtLeastOneRequiredControlPresent == false) - { - return base.ArrangeOverride(arrangeBounds); - } - - if (this.IsCollapsed) - { - return base.ArrangeOverride(arrangeBounds); - } - - this.itemsContainer.Arrange(this.itemsRect); - this.headerHolder.Arrange(this.headerRect); - this.quickAccessToolbarHolder.Arrange(this.quickAccessToolbarRect); - return arrangeBounds; - } - - #endregion - - #region Private methods - - // Update items size and positions - private void Update(Size constraint) - { - var visibleGroups = this.Items.OfType() - .Where(group => group.InnerVisibility == Visibility.Visible && group.Items.Count > 0) - .ToList(); - - var infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); - - var canRibbonTabControlScroll = false; - - // Defensively try to find out if the RibbonTabControl can scroll - if (visibleGroups.Count > 0) - { - var firstVisibleItem = visibleGroups.First().FirstVisibleItem; - - if (firstVisibleItem != null - && firstVisibleItem.Parent != null) - { - canRibbonTabControlScroll = ((RibbonTabControl)firstVisibleItem.Parent).CanScroll; - } - } - - if (visibleGroups.Count == 0 - || canRibbonTabControlScroll) - { - // Collapse itemRect - this.itemsRect = new Rect(0, 0, 0, 0); - // Set quick launch toolbar and header position and size - this.quickAccessToolbarHolder.Measure(infinity); - - if (constraint.Width <= this.quickAccessToolbarHolder.DesiredSize.Width + 50) - { - this.quickAccessToolbarRect = new Rect(0, 0, Math.Max(0, constraint.Width - 50), this.quickAccessToolbarHolder.DesiredSize.Height); - this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); - } - - if (constraint.Width > this.quickAccessToolbarHolder.DesiredSize.Width + 50) - { - this.quickAccessToolbarRect = new Rect(0, 0, this.quickAccessToolbarHolder.DesiredSize.Width, this.quickAccessToolbarHolder.DesiredSize.Height); - this.headerHolder.Measure(infinity); - var allTextWidth = constraint.Width - this.quickAccessToolbarHolder.DesiredSize.Width; - - if (this.HeaderAlignment == HorizontalAlignment.Left) - { - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width, 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else if (this.HeaderAlignment == HorizontalAlignment.Center) - { - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth / 2 - this.headerHolder.DesiredSize.Width / 2), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else if (this.HeaderAlignment == HorizontalAlignment.Right) - { - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth - this.headerHolder.DesiredSize.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else if (this.HeaderAlignment == HorizontalAlignment.Stretch) - { - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width, 0, allTextWidth, constraint.Height); - } - } - else - { - this.headerRect = new Rect(Math.Max(0, constraint.Width - 50), 0, 50, constraint.Height); - } - } - else - { - // Set items container size and position - var firstItem = visibleGroups.First().FirstVisibleItem; - var lastItem = visibleGroups.Last().LastVisibleItem; - - var startX = firstItem.TranslatePoint(new Point(0, 0), this).X; - var endX = lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X; - - //Get minimum x point (workaround) - foreach (var group in visibleGroups) - { - firstItem = group.FirstVisibleItem; - - if (firstItem != null) - { - if (firstItem.TranslatePoint(new Point(0, 0), this).X < startX) - { - startX = firstItem.TranslatePoint(new Point(0, 0), this).X; - } - } - - lastItem = group.LastVisibleItem; - - if (lastItem != null) - { - if (lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X > endX) - { - endX = lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X; - } - } - } - - // Ensure that startX and endX are never negative - startX = Math.Max(0, startX); - endX = Math.Max(0, endX); - - //Looks like thr titlebar things are ordered in an other way - if (DoubleUtil.AreClose(startX, endX) == false) - { - this.itemsRect = new Rect(startX, 0, Math.Max(0, Math.Min(endX, constraint.Width) - startX), constraint.Height); - } - - // Set quick launch toolbar position and size - this.quickAccessToolbarHolder.Measure(infinity); - - var quickAccessToolbarWidth = this.quickAccessToolbarHolder.DesiredSize.Width; - this.quickAccessToolbarRect = new Rect(0, 0, Math.Min(quickAccessToolbarWidth, startX), this.quickAccessToolbarHolder.DesiredSize.Height); - - if (quickAccessToolbarWidth > startX) - { - this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); - this.quickAccessToolbarRect = new Rect(0, 0, this.quickAccessToolbarHolder.DesiredSize.Width, this.quickAccessToolbarHolder.DesiredSize.Height); - quickAccessToolbarWidth = this.quickAccessToolbarHolder.DesiredSize.Width; - } - - // Set header - this.headerHolder.Measure(infinity); - - switch (this.HeaderAlignment) - { - case HorizontalAlignment.Left: - { - if (startX - quickAccessToolbarWidth > 150) - { - var allTextWidth = startX - quickAccessToolbarWidth; - this.headerRect = new Rect(this.quickAccessToolbarRect.Width, 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else - { - var allTextWidth = Math.Max(0, constraint.Width - endX); - this.headerRect = new Rect(Math.Min(endX, constraint.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - } - break; - - case HorizontalAlignment.Center: - { - var allTextWidthRight = Math.Max(0, constraint.Width - endX); - var allTextWidthLeft = Math.Max(0, startX - quickAccessToolbarWidth); - var fitsRightButNotLeft = (allTextWidthRight >= this.headerHolder.DesiredSize.Width && allTextWidthLeft < this.headerHolder.DesiredSize.Width); - - if (((startX - quickAccessToolbarWidth < 150 || fitsRightButNotLeft) && (startX - quickAccessToolbarWidth > 0) && (startX - quickAccessToolbarWidth < constraint.Width - endX)) || (endX < constraint.Width / 2)) - { - this.headerRect = new Rect(Math.Min(Math.Max(endX, constraint.Width / 2 - this.headerHolder.DesiredSize.Width / 2), constraint.Width), 0, Math.Min(allTextWidthRight, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else - { - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidthLeft / 2 - this.headerHolder.DesiredSize.Width / 2), 0, Math.Min(allTextWidthLeft, this.headerHolder.DesiredSize.Width), constraint.Height); - } - } - break; - - case HorizontalAlignment.Right: - { - if (startX - quickAccessToolbarWidth > 150) - { - var allTextWidth = Math.Max(0, startX - quickAccessToolbarWidth); - this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth - this.headerHolder.DesiredSize.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - else - { - var allTextWidth = Math.Max(0, constraint.Width - endX); - this.headerRect = new Rect(Math.Min(Math.Max(endX, constraint.Width - this.headerHolder.DesiredSize.Width), constraint.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); - } - } - break; - - case HorizontalAlignment.Stretch: - { - if (startX - quickAccessToolbarWidth > 150) - { - var allTextWidth = startX - quickAccessToolbarWidth; - this.headerRect = new Rect(this.quickAccessToolbarRect.Width, 0, allTextWidth, constraint.Height); - } - else - { - var allTextWidth = Math.Max(0, constraint.Width - endX); - this.headerRect = new Rect(Math.Min(endX, constraint.Width), 0, allTextWidth, constraint.Height); - } - } - break; - } - } - - this.headerRect.Width = this.headerRect.Width + 2; - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using Fluent.Internal; + +namespace Fluent +{ + /// + /// Represents title bar + /// + [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(RibbonContextualTabGroup))] + [TemplatePart(Name = "PART_QuickAccessToolbarHolder", Type = typeof(FrameworkElement))] + [TemplatePart(Name = "PART_HeaderHolder", Type = typeof(FrameworkElement))] + [TemplatePart(Name = "PART_ItemsContainer", Type = typeof(Panel))] + public class RibbonTitleBar : HeaderedItemsControl + { + #region Fields + + // Quick access toolbar holder + private FrameworkElement quickAccessToolbarHolder; + // Header holder + private FrameworkElement headerHolder; + // Items container + private Panel itemsContainer; + // Quick access toolbar rect + private Rect quickAccessToolbarRect; + // Header rect + private Rect headerRect; + // Items rect + private Rect itemsRect; + + #endregion + + #region Properties + + /// + /// Gets or sets quick access toolbar + /// + public UIElement QuickAccessToolBar + { + get { return (UIElement)this.GetValue(QuickAccessToolBarProperty); } + set { this.SetValue(QuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for QuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty QuickAccessToolBarProperty = + DependencyProperty.Register("QuickAccessToolBar", typeof(UIElement), typeof(RibbonTitleBar), new UIPropertyMetadata(null, OnQuickAccessToolbarChanged)); + + // Handles QuickAccessToolBar property chages + private static void OnQuickAccessToolbarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var titleBar = (RibbonTitleBar)d; + titleBar.InvalidateMeasure(); + } + + /// + /// Gets or sets header alignment + /// + public HorizontalAlignment HeaderAlignment + { + get { return (HorizontalAlignment)this.GetValue(HeaderAlignmentProperty); } + set { this.SetValue(HeaderAlignmentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HeaderAlignment. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderAlignmentProperty = + DependencyProperty.Register("HeaderAlignment", typeof(HorizontalAlignment), typeof(RibbonTitleBar), new UIPropertyMetadata(HorizontalAlignment.Center)); + + /// + /// Defines whether title bar is collapsed + /// + public bool IsCollapsed + { + get { return (bool)this.GetValue(IsCollapsedProperty); } + set { this.SetValue(IsCollapsedProperty, value); } + } + + /// + /// DependencyProperty for + /// + public static readonly DependencyProperty IsCollapsedProperty = + DependencyProperty.Register("IsCollapsed", typeof(bool), typeof(RibbonTitleBar), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); + + private bool isAtLeastOneRequiredControlPresent; + + /// + /// Using a DependencyProperty as the backing store for HideContextTabs. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HideContextTabsProperty = + DependencyProperty.Register("HideContextTabs", typeof(bool), typeof(RibbonTitleBar), new PropertyMetadata(false)); + + /// + /// Gets or sets whether context tabs are hidden. + /// + public bool HideContextTabs + { + get { return (bool)this.GetValue(HideContextTabsProperty); } + set { this.SetValue(HideContextTabsProperty, value); } + } + + #endregion + + #region Initialize + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonTitleBar() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonTitleBar), new FrameworkPropertyMetadata(typeof(RibbonTitleBar))); + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { + return new RibbonContextualTabGroup(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// true if the item is (or is eligible to be) its own container; otherwise, false. + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is RibbonContextualTabGroup; + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes + /// call System.Windows.FrameworkElement.ApplyTemplate(). + /// + public override void OnApplyTemplate() + { + this.quickAccessToolbarHolder = this.GetTemplateChild("PART_QuickAccessToolbarHolder") as FrameworkElement; + this.headerHolder = this.GetTemplateChild("PART_HeaderHolder") as FrameworkElement; + this.itemsContainer = this.GetTemplateChild("PART_ItemsContainer") as Panel; + + this.isAtLeastOneRequiredControlPresent = this.quickAccessToolbarHolder != null + || this.headerHolder != null + || this.itemsContainer != null; + } + + /// + /// Called to remeasure a control. + /// + /// The maximum size that the method can return. + /// The size of the control, up to the maximum specified by constraint. + protected override Size MeasureOverride(Size constraint) + { + if (this.isAtLeastOneRequiredControlPresent == false) + { + return base.MeasureOverride(constraint); + } + + if (this.IsCollapsed) + { + return base.MeasureOverride(constraint); + } + + var resultSize = constraint; + + if (double.IsPositiveInfinity(resultSize.Width) + || double.IsPositiveInfinity(resultSize.Height)) + { + resultSize = base.MeasureOverride(resultSize); + } + + this.Update(resultSize); + + this.itemsContainer.Measure(this.itemsRect.Size); + this.headerHolder.Measure(this.headerRect.Size); + this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); + + var maxHeight = Math.Max(Math.Max(this.itemsRect.Height, this.headerRect.Height), this.quickAccessToolbarRect.Height); + var width = this.itemsRect.Width + this.headerRect.Width + this.quickAccessToolbarRect.Width; + + return new Size(width, maxHeight); + } + + /// + /// Called to arrange and size the content of a System.Windows.Controls.Control object. + /// + /// The computed size that is used to arrange the content. + /// The size of the control. + protected override Size ArrangeOverride(Size arrangeBounds) + { + if (this.isAtLeastOneRequiredControlPresent == false) + { + return base.ArrangeOverride(arrangeBounds); + } + + if (this.IsCollapsed) + { + return base.ArrangeOverride(arrangeBounds); + } + + this.itemsContainer.Arrange(this.itemsRect); + this.headerHolder.Arrange(this.headerRect); + this.quickAccessToolbarHolder.Arrange(this.quickAccessToolbarRect); + return arrangeBounds; + } + + #endregion + + #region Private methods + + // Update items size and positions + private void Update(Size constraint) + { + var visibleGroups = this.Items.OfType() + .Where(group => group.InnerVisibility == Visibility.Visible && group.Items.Count > 0) + .ToList(); + + var infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); + + var canRibbonTabControlScroll = false; + + // Defensively try to find out if the RibbonTabControl can scroll + if (visibleGroups.Count > 0) + { + var firstVisibleItem = visibleGroups.First().FirstVisibleItem; + + if (firstVisibleItem != null + && firstVisibleItem.Parent != null) + { + canRibbonTabControlScroll = ((RibbonTabControl)firstVisibleItem.Parent).CanScroll; + } + } + + if (visibleGroups.Count == 0 + || canRibbonTabControlScroll) + { + // Collapse itemRect + this.itemsRect = new Rect(0, 0, 0, 0); + // Set quick launch toolbar and header position and size + this.quickAccessToolbarHolder.Measure(infinity); + + if (constraint.Width <= this.quickAccessToolbarHolder.DesiredSize.Width + 50) + { + this.quickAccessToolbarRect = new Rect(0, 0, Math.Max(0, constraint.Width - 50), this.quickAccessToolbarHolder.DesiredSize.Height); + this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); + } + + if (constraint.Width > this.quickAccessToolbarHolder.DesiredSize.Width + 50) + { + this.quickAccessToolbarRect = new Rect(0, 0, this.quickAccessToolbarHolder.DesiredSize.Width, this.quickAccessToolbarHolder.DesiredSize.Height); + this.headerHolder.Measure(infinity); + var allTextWidth = constraint.Width - this.quickAccessToolbarHolder.DesiredSize.Width; + + if (this.HeaderAlignment == HorizontalAlignment.Left) + { + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width, 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else if (this.HeaderAlignment == HorizontalAlignment.Center) + { + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth / 2 - this.headerHolder.DesiredSize.Width / 2), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else if (this.HeaderAlignment == HorizontalAlignment.Right) + { + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth - this.headerHolder.DesiredSize.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else if (this.HeaderAlignment == HorizontalAlignment.Stretch) + { + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width, 0, allTextWidth, constraint.Height); + } + } + else + { + this.headerRect = new Rect(Math.Max(0, constraint.Width - 50), 0, 50, constraint.Height); + } + } + else + { + // Set items container size and position + var firstItem = visibleGroups.First().FirstVisibleItem; + var lastItem = visibleGroups.Last().LastVisibleItem; + + var startX = firstItem.TranslatePoint(new Point(0, 0), this).X; + var endX = lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X; + + //Get minimum x point (workaround) + foreach (var group in visibleGroups) + { + firstItem = group.FirstVisibleItem; + + if (firstItem != null) + { + if (firstItem.TranslatePoint(new Point(0, 0), this).X < startX) + { + startX = firstItem.TranslatePoint(new Point(0, 0), this).X; + } + } + + lastItem = group.LastVisibleItem; + + if (lastItem != null) + { + if (lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X > endX) + { + endX = lastItem.TranslatePoint(new Point(lastItem.DesiredSize.Width, 0), this).X; + } + } + } + + // Ensure that startX and endX are never negative + startX = Math.Max(0, startX); + endX = Math.Max(0, endX); + + //Looks like thr titlebar things are ordered in an other way + if (DoubleUtil.AreClose(startX, endX) == false) + { + this.itemsRect = new Rect(startX, 0, Math.Max(0, Math.Min(endX, constraint.Width) - startX), constraint.Height); + } + + // Set quick launch toolbar position and size + this.quickAccessToolbarHolder.Measure(infinity); + + var quickAccessToolbarWidth = this.quickAccessToolbarHolder.DesiredSize.Width; + this.quickAccessToolbarRect = new Rect(0, 0, Math.Min(quickAccessToolbarWidth, startX), this.quickAccessToolbarHolder.DesiredSize.Height); + + if (quickAccessToolbarWidth > startX) + { + this.quickAccessToolbarHolder.Measure(this.quickAccessToolbarRect.Size); + this.quickAccessToolbarRect = new Rect(0, 0, this.quickAccessToolbarHolder.DesiredSize.Width, this.quickAccessToolbarHolder.DesiredSize.Height); + quickAccessToolbarWidth = this.quickAccessToolbarHolder.DesiredSize.Width; + } + + // Set header + this.headerHolder.Measure(infinity); + + switch (this.HeaderAlignment) + { + case HorizontalAlignment.Left: + { + if (startX - quickAccessToolbarWidth > 150) + { + var allTextWidth = startX - quickAccessToolbarWidth; + this.headerRect = new Rect(this.quickAccessToolbarRect.Width, 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else + { + var allTextWidth = Math.Max(0, constraint.Width - endX); + this.headerRect = new Rect(Math.Min(endX, constraint.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + } + break; + + case HorizontalAlignment.Center: + { + var allTextWidthRight = Math.Max(0, constraint.Width - endX); + var allTextWidthLeft = Math.Max(0, startX - quickAccessToolbarWidth); + var fitsRightButNotLeft = (allTextWidthRight >= this.headerHolder.DesiredSize.Width && allTextWidthLeft < this.headerHolder.DesiredSize.Width); + + if (((startX - quickAccessToolbarWidth < 150 || fitsRightButNotLeft) && (startX - quickAccessToolbarWidth > 0) && (startX - quickAccessToolbarWidth < constraint.Width - endX)) || (endX < constraint.Width / 2)) + { + this.headerRect = new Rect(Math.Min(Math.Max(endX, constraint.Width / 2 - this.headerHolder.DesiredSize.Width / 2), constraint.Width), 0, Math.Min(allTextWidthRight, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else + { + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidthLeft / 2 - this.headerHolder.DesiredSize.Width / 2), 0, Math.Min(allTextWidthLeft, this.headerHolder.DesiredSize.Width), constraint.Height); + } + } + break; + + case HorizontalAlignment.Right: + { + if (startX - quickAccessToolbarWidth > 150) + { + var allTextWidth = Math.Max(0, startX - quickAccessToolbarWidth); + this.headerRect = new Rect(this.quickAccessToolbarHolder.DesiredSize.Width + Math.Max(0, allTextWidth - this.headerHolder.DesiredSize.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + else + { + var allTextWidth = Math.Max(0, constraint.Width - endX); + this.headerRect = new Rect(Math.Min(Math.Max(endX, constraint.Width - this.headerHolder.DesiredSize.Width), constraint.Width), 0, Math.Min(allTextWidth, this.headerHolder.DesiredSize.Width), constraint.Height); + } + } + break; + + case HorizontalAlignment.Stretch: + { + if (startX - quickAccessToolbarWidth > 150) + { + var allTextWidth = startX - quickAccessToolbarWidth; + this.headerRect = new Rect(this.quickAccessToolbarRect.Width, 0, allTextWidth, constraint.Height); + } + else + { + var allTextWidth = Math.Max(0, constraint.Width - endX); + this.headerRect = new Rect(Math.Min(endX, constraint.Width), 0, allTextWidth, constraint.Height); + } + } + break; + } + } + + this.headerRect.Width = this.headerRect.Width + 2; + } + + #endregion + } +} diff --git a/Fluent/Controls/RibbonToolBar.cs b/Fluent.Ribbon/Controls/RibbonToolBar.cs similarity index 97% rename from Fluent/Controls/RibbonToolBar.cs rename to Fluent.Ribbon/Controls/RibbonToolBar.cs index e966b91d3..531dc6df0 100644 --- a/Fluent/Controls/RibbonToolBar.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBar.cs @@ -1,582 +1,582 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Markup; -using System.Windows.Media; - -namespace Fluent -{ - using Fluent.Extensibility; - - /// - /// Represent panel for group box panel - /// - [ContentProperty("Children")] - public class RibbonToolBar : RibbonControl, IRibbonSizeChangedSink - { - #region Fields - - // User defined children - readonly ObservableCollection children = new ObservableCollection(); - // User defined layout definitions - readonly ObservableCollection layoutDefinitions = - new ObservableCollection(); - - // Actual children - readonly List actualChildren = new List(); - // Designates that rebuilding of visual & logical children is required - bool rebuildVisualAndLogicalChildren = true; - - #endregion - - #region Properties - - #region Separator Style - - /// - /// Gets or sets style for the separator - /// - public Style SeparatorStyle - { - get { return (Style)this.GetValue(SeparatorStyleProperty); } - set { this.SetValue(SeparatorStyleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SeparatorStyle. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SeparatorStyleProperty = - DependencyProperty.Register("SeparatorStyle", typeof(Style), - typeof(RibbonToolBar), new UIPropertyMetadata(null, OnSeparatorStyleChanged)); - - static void OnSeparatorStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonToolBar toolBar = (RibbonToolBar)d; - toolBar.rebuildVisualAndLogicalChildren = true; - toolBar.InvalidateMeasure(); - } - - #endregion - - /// - /// Gets children - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ObservableCollection Children - { - get { return this.children; } - } - - /// - /// Gets particular rules for layout in this group box panel - /// - public ObservableCollection LayoutDefinitions - { - get { return this.layoutDefinitions; } - } - - #endregion - - #region Logical & Visual Tree - - /// - /// Gets the number of visual child elements within this element. - /// - protected override int VisualChildrenCount - { - get - { - if (this.layoutDefinitions.Count == 0) return this.children.Count; - if (this.rebuildVisualAndLogicalChildren) - { - //TODO: Exception during theme changing - // UpdateLayout(); - this.InvalidateMeasure(); - } - return this.actualChildren.Count; - } - } - - /// - /// Overrides System.Windows.Media.Visual.GetVisualChild(System.Int32), - /// and returns a child at the specified index from a collection of child elements. - /// - /// The zero-based index of the requested - /// child element in the collection - /// The requested child element. This should not return null; - /// if the provided index is out of range, an exception is thrown - protected override Visual GetVisualChild(int index) - { - if (this.layoutDefinitions.Count == 0) return this.children[index]; - if (this.rebuildVisualAndLogicalChildren) - { - // UpdateLayout(); - this.InvalidateMeasure(); - } - return this.actualChildren[index]; - } - - /// - /// Gets an enumerator for logical child elements of this element - /// - protected override IEnumerator LogicalChildren - { - get - { - return this.children.GetEnumerator(); - } - } - - #endregion - - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonToolBar() - { - // Override default style - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(typeof(RibbonToolBar))); - // Disable QAT for this control - CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(false)); - StyleProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonToolBar)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public RibbonToolBar() - { - this.children.CollectionChanged += this.OnChildrenCollectionChanged; - this.layoutDefinitions.CollectionChanged += this.OnLayoutDefinitionsChanged; - } - - void OnLayoutDefinitionsChanged(object sender, NotifyCollectionChangedEventArgs e) - { - this.rebuildVisualAndLogicalChildren = true; - this.InvalidateMeasure(); - } - - void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - // Children have changed, reset layouts - this.rebuildVisualAndLogicalChildren = true; - this.InvalidateMeasure(); - } - - #endregion - - #region Methods - - /// - /// Gets current used layout definition (or null if no present definitions) - /// - /// Layout definition or null - internal RibbonToolBarLayoutDefinition GetCurrentLayoutDefinition() - { - if (this.layoutDefinitions.Count == 0) return null; - if (this.layoutDefinitions.Count == 1) return this.layoutDefinitions[0]; - - foreach (RibbonToolBarLayoutDefinition definition in this.layoutDefinitions) - { - if (RibbonProperties.GetSize(definition) == RibbonProperties.GetSize(this)) return definition; - } - - // TODO: try to find a better definition - return this.layoutDefinitions[0]; - } - - #endregion - - #region Size Property Changing - - /// - /// Handles size property changing - /// - /// Previous value - /// Current value - public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) - { - foreach (var frameworkElement in this.actualChildren) - { - RibbonProperties.SetSize(frameworkElement, current); - } - - this.rebuildVisualAndLogicalChildren = true; - this.InvalidateMeasure(); - } - - #endregion - - #region Layout Overriding - - /// - /// Measures all of the RibbonGroupBox, and resize them appropriately - /// to fit within the available room - /// - /// The available size that - /// this element can give to child elements. - /// The size that the panel determines it needs during - /// layout, based on its calculations of child element sizes. - /// - protected override Size MeasureOverride(Size availableSize) - { - RibbonToolBarLayoutDefinition layoutDefinition = this.GetCurrentLayoutDefinition(); - - // Rebuilding actual children (visual & logical) - if (this.rebuildVisualAndLogicalChildren) - { - // Clear previous children - foreach (FrameworkElement child in this.actualChildren) - { - RibbonToolBarControlGroup controlGroup = child as RibbonToolBarControlGroup; - if (controlGroup != null) controlGroup.Items.Clear(); - this.RemoveVisualChild(child); - this.RemoveLogicalChild(child); - } - this.actualChildren.Clear(); - this.cachedControlGroups.Clear(); - } - - if (layoutDefinition == null) - { - if (this.rebuildVisualAndLogicalChildren) - { - // If default layout is used add all children - foreach (FrameworkElement child in this.Children) - { - this.actualChildren.Add(child); - this.AddVisualChild(child); - this.AddLogicalChild(child); - } - this.rebuildVisualAndLogicalChildren = false; - } - return this.WrapPanelLayuot(availableSize, true); - } - else - { - Size result = this.CustomLayout(layoutDefinition, availableSize, true, this.rebuildVisualAndLogicalChildren); - this.rebuildVisualAndLogicalChildren = false; - return result; - } - - - } - - /// - /// When overridden in a derived class, positions child elements and determines - /// a size for a System.Windows.FrameworkElement derived class. - /// - /// The final area within the parent that this - /// element should use to arrange itself and its children. - /// The actual size used. - protected override Size ArrangeOverride(Size finalSize) - { - RibbonToolBarLayoutDefinition layoutDefinition = this.GetCurrentLayoutDefinition(); - if (layoutDefinition == null) return this.WrapPanelLayuot(finalSize, false); - return this.CustomLayout(layoutDefinition, finalSize, false, false); - } - - - #region Wrap Panel Layout - - /// - /// Unified method for wrap panel logic - /// - /// Available or final size - /// Pass true if measure required; pass false if arrange required - /// Final size - Size WrapPanelLayuot(Size availableSize, bool measure) - { - bool arrange = !measure; - double availableHeight = double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height; - - double currentheight = 0; - double columnWidth = 0; - - double resultWidth = 0; - double resultHeight = 0; - - Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); - foreach (FrameworkElement child in this.children) - { - // Measuring - if (measure) child.Measure(infinity); - - if (currentheight + child.DesiredSize.Height > availableHeight) - { - // Move to the next column - resultHeight = Math.Max(resultHeight, currentheight); - resultWidth += columnWidth; - currentheight = 0; - columnWidth = 0; - } - - // Arranging - if (arrange) child.Arrange(new Rect( - resultWidth, - currentheight, - child.DesiredSize.Width, - child.DesiredSize.Height)); - - columnWidth = Math.Max(columnWidth, child.DesiredSize.Width); - currentheight += child.DesiredSize.Height; - } - - return new Size(resultWidth + columnWidth, resultHeight); - } - - #endregion - - #region Control and Group Creation from a Definition - - FrameworkElement GetControl(RibbonToolBarControlDefinition controlDefinition) - { - string name = controlDefinition.Target; - return this.Children.FirstOrDefault(x => x.Name == name); - } - - Dictionary cachedControlGroups = new Dictionary(); - RibbonToolBarControlGroup GetControlGroup(RibbonToolBarControlGroupDefinition controlGroupDefinition) - { - RibbonToolBarControlGroup controlGroup = null; - if (!this.cachedControlGroups.TryGetValue(controlGroupDefinition, out controlGroup)) - { - controlGroup = new RibbonToolBarControlGroup(); - // Add items to the group - foreach (RibbonToolBarControlDefinition child in controlGroupDefinition.Children) - { - controlGroup.Items.Add(this.GetControl(child)); - } - this.cachedControlGroups.Add(controlGroupDefinition, controlGroup); - } - return controlGroup; - } - - #endregion - - #region Custom Layout - - // Cached separators (clear & set in Measure pass) - Dictionary separatorCache = new Dictionary(); - - /// - /// Layout logic for the given layout definition - /// - /// Current layout definition - /// Available or final size - /// Pass true if measure required; pass false if arrange required - /// Determines whether we have to add children to the logical and visual tree - /// Final size - Size CustomLayout(RibbonToolBarLayoutDefinition layoutDefinition, Size availableSize, bool measure, bool addchildren) - { - bool arrange = !measure; - double availableHeight = double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height; - - // Clear separator cahce - if (addchildren) - this.separatorCache.Clear(); - - // Get the first control and measure, its height accepts as row height - double rowHeight = this.GetRowHeight(layoutDefinition); - - - // Calculate whitespace - int rowCountInColumn = Math.Min(layoutDefinition.RowCount, layoutDefinition.Rows.Count); - double whitespace = (availableHeight - ((double)rowCountInColumn * rowHeight)) / (double)(rowCountInColumn + 1); - - double y = 0; - double x = 0; - double currentRowBegin = 0; - double currentMaxX = 0; - double maxy = 0; - for(int rowIndex = 0; rowIndex < layoutDefinition.Rows.Count; rowIndex++) - { - RibbonToolBarRow row = layoutDefinition.Rows[rowIndex]; - - x = currentRowBegin; - - if (rowIndex % rowCountInColumn == 0) - { - // Reset vars at new column - x = currentRowBegin = currentMaxX; - y = 0; - - if (rowIndex != 0) - { - #region Add separator - - Separator separator = null; - if (!this.separatorCache.TryGetValue(rowIndex, out separator)) - { - separator = new Separator(); - separator.Style = this.SeparatorStyle; - this.separatorCache.Add(rowIndex, separator); - } - if (measure) - { - separator.Height = availableHeight - separator.Margin.Bottom - separator.Margin.Top; - separator.Measure(availableSize); - } - if (arrange) separator.Arrange(new Rect(x, y, - separator.DesiredSize.Width, - separator.DesiredSize.Height)); - x += separator.DesiredSize.Width; - - if (addchildren) - { - // Add control in the children - this.AddVisualChild(separator); - this.AddLogicalChild(separator); - this.actualChildren.Add(separator); - } - - #endregion - } - } - y += whitespace; - - - // Measure & arrange new row - for(int i = 0; i < row.Children.Count; i++) - { - if (row.Children[i] is RibbonToolBarControlDefinition) - { - // Control Definition Case - RibbonToolBarControlDefinition controlDefinition = - (RibbonToolBarControlDefinition) row.Children[i]; - FrameworkElement control = this.GetControl(controlDefinition); - if (control == null) continue; - - if (addchildren) - { - // Add control in the children - this.AddVisualChild(control); - this.AddLogicalChild(control); - this.actualChildren.Add(control); - } - - if (measure) - { - // Apply Control Definition Properties - RibbonProperties.SetSize(control, RibbonProperties.GetSize(controlDefinition)); - control.Width = controlDefinition.Width; - control.Measure(availableSize); - } - if (arrange) - { - control.Arrange(new Rect(x, y, - control.DesiredSize.Width, - control.DesiredSize.Height)); - } - - x += control.DesiredSize.Width; - } - if (row.Children[i] is RibbonToolBarControlGroupDefinition) - { - // Control Definition Case - RibbonToolBarControlGroupDefinition controlGroupDefinition = - (RibbonToolBarControlGroupDefinition)row.Children[i]; - - RibbonToolBarControlGroup control = this.GetControlGroup(controlGroupDefinition); - - if (addchildren) - { - // Add control in the children - this.AddVisualChild(control); - this.AddLogicalChild(control); - this.actualChildren.Add(control); - } - - if (measure) - { - // Apply Control Definition Properties - control.IsFirstInRow = (i == 0); - control.IsLastInRow = (i == row.Children.Count - 1); - control.Measure(availableSize); - } - if (arrange) - { - control.Arrange(new Rect(x, y, - control.DesiredSize.Width, - control.DesiredSize.Height)); - } - - x += control.DesiredSize.Width; - } - } - - y += rowHeight; - if (currentMaxX < x) currentMaxX = x; - if (maxy < y) maxy = y; - } - - return new Size(currentMaxX, maxy + whitespace); - } - - // Get the first control and measure, its height accepts as row height - double GetRowHeight(RibbonToolBarLayoutDefinition layoutDefinition) - { - const double defaultRowHeight = 0; - foreach (RibbonToolBarRow row in layoutDefinition.Rows) - { - foreach (DependencyObject item in row.Children) - { - RibbonToolBarControlDefinition controlDefinition = item as RibbonToolBarControlDefinition; - RibbonToolBarControlGroupDefinition controlGroupDefinition = item as RibbonToolBarControlGroupDefinition; - FrameworkElement control = null; - if (controlDefinition != null) control = this.GetControl(controlDefinition); - else if (controlGroupDefinition != null) - control = this.GetControlGroup(controlGroupDefinition); - - if (control == null) return defaultRowHeight; - control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); - return control.DesiredSize.Height; - } - } - return defaultRowHeight; - } - - #endregion - - #endregion - - #region QAT Support - - // (!) RibbonToolBar must not to be in QAT - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - return new Control(); - } - - #endregion - } +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Windows.Media; + +namespace Fluent +{ + using Fluent.Extensibility; + + /// + /// Represent panel for group box panel + /// + [ContentProperty("Children")] + public class RibbonToolBar : RibbonControl, IRibbonSizeChangedSink + { + #region Fields + + // User defined children + readonly ObservableCollection children = new ObservableCollection(); + // User defined layout definitions + readonly ObservableCollection layoutDefinitions = + new ObservableCollection(); + + // Actual children + readonly List actualChildren = new List(); + // Designates that rebuilding of visual & logical children is required + bool rebuildVisualAndLogicalChildren = true; + + #endregion + + #region Properties + + #region Separator Style + + /// + /// Gets or sets style for the separator + /// + public Style SeparatorStyle + { + get { return (Style)this.GetValue(SeparatorStyleProperty); } + set { this.SetValue(SeparatorStyleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SeparatorStyle. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SeparatorStyleProperty = + DependencyProperty.Register("SeparatorStyle", typeof(Style), + typeof(RibbonToolBar), new UIPropertyMetadata(null, OnSeparatorStyleChanged)); + + static void OnSeparatorStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonToolBar toolBar = (RibbonToolBar)d; + toolBar.rebuildVisualAndLogicalChildren = true; + toolBar.InvalidateMeasure(); + } + + #endregion + + /// + /// Gets children + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ObservableCollection Children + { + get { return this.children; } + } + + /// + /// Gets particular rules for layout in this group box panel + /// + public ObservableCollection LayoutDefinitions + { + get { return this.layoutDefinitions; } + } + + #endregion + + #region Logical & Visual Tree + + /// + /// Gets the number of visual child elements within this element. + /// + protected override int VisualChildrenCount + { + get + { + if (this.layoutDefinitions.Count == 0) return this.children.Count; + if (this.rebuildVisualAndLogicalChildren) + { + //TODO: Exception during theme changing + // UpdateLayout(); + this.InvalidateMeasure(); + } + return this.actualChildren.Count; + } + } + + /// + /// Overrides System.Windows.Media.Visual.GetVisualChild(System.Int32), + /// and returns a child at the specified index from a collection of child elements. + /// + /// The zero-based index of the requested + /// child element in the collection + /// The requested child element. This should not return null; + /// if the provided index is out of range, an exception is thrown + protected override Visual GetVisualChild(int index) + { + if (this.layoutDefinitions.Count == 0) return this.children[index]; + if (this.rebuildVisualAndLogicalChildren) + { + // UpdateLayout(); + this.InvalidateMeasure(); + } + return this.actualChildren[index]; + } + + /// + /// Gets an enumerator for logical child elements of this element + /// + protected override IEnumerator LogicalChildren + { + get + { + return this.children.GetEnumerator(); + } + } + + #endregion + + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonToolBar() + { + // Override default style + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(typeof(RibbonToolBar))); + // Disable QAT for this control + CanAddToQuickAccessToolBarProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(false)); + StyleProperty.OverrideMetadata(typeof(RibbonToolBar), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonToolBar)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public RibbonToolBar() + { + this.children.CollectionChanged += this.OnChildrenCollectionChanged; + this.layoutDefinitions.CollectionChanged += this.OnLayoutDefinitionsChanged; + } + + void OnLayoutDefinitionsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + this.rebuildVisualAndLogicalChildren = true; + this.InvalidateMeasure(); + } + + void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + // Children have changed, reset layouts + this.rebuildVisualAndLogicalChildren = true; + this.InvalidateMeasure(); + } + + #endregion + + #region Methods + + /// + /// Gets current used layout definition (or null if no present definitions) + /// + /// Layout definition or null + internal RibbonToolBarLayoutDefinition GetCurrentLayoutDefinition() + { + if (this.layoutDefinitions.Count == 0) return null; + if (this.layoutDefinitions.Count == 1) return this.layoutDefinitions[0]; + + foreach (RibbonToolBarLayoutDefinition definition in this.layoutDefinitions) + { + if (RibbonProperties.GetSize(definition) == RibbonProperties.GetSize(this)) return definition; + } + + // TODO: try to find a better definition + return this.layoutDefinitions[0]; + } + + #endregion + + #region Size Property Changing + + /// + /// Handles size property changing + /// + /// Previous value + /// Current value + public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) + { + foreach (var frameworkElement in this.actualChildren) + { + RibbonProperties.SetSize(frameworkElement, current); + } + + this.rebuildVisualAndLogicalChildren = true; + this.InvalidateMeasure(); + } + + #endregion + + #region Layout Overriding + + /// + /// Measures all of the RibbonGroupBox, and resize them appropriately + /// to fit within the available room + /// + /// The available size that + /// this element can give to child elements. + /// The size that the panel determines it needs during + /// layout, based on its calculations of child element sizes. + /// + protected override Size MeasureOverride(Size availableSize) + { + RibbonToolBarLayoutDefinition layoutDefinition = this.GetCurrentLayoutDefinition(); + + // Rebuilding actual children (visual & logical) + if (this.rebuildVisualAndLogicalChildren) + { + // Clear previous children + foreach (FrameworkElement child in this.actualChildren) + { + RibbonToolBarControlGroup controlGroup = child as RibbonToolBarControlGroup; + if (controlGroup != null) controlGroup.Items.Clear(); + this.RemoveVisualChild(child); + this.RemoveLogicalChild(child); + } + this.actualChildren.Clear(); + this.cachedControlGroups.Clear(); + } + + if (layoutDefinition == null) + { + if (this.rebuildVisualAndLogicalChildren) + { + // If default layout is used add all children + foreach (FrameworkElement child in this.Children) + { + this.actualChildren.Add(child); + this.AddVisualChild(child); + this.AddLogicalChild(child); + } + this.rebuildVisualAndLogicalChildren = false; + } + return this.WrapPanelLayuot(availableSize, true); + } + else + { + Size result = this.CustomLayout(layoutDefinition, availableSize, true, this.rebuildVisualAndLogicalChildren); + this.rebuildVisualAndLogicalChildren = false; + return result; + } + + + } + + /// + /// When overridden in a derived class, positions child elements and determines + /// a size for a System.Windows.FrameworkElement derived class. + /// + /// The final area within the parent that this + /// element should use to arrange itself and its children. + /// The actual size used. + protected override Size ArrangeOverride(Size finalSize) + { + RibbonToolBarLayoutDefinition layoutDefinition = this.GetCurrentLayoutDefinition(); + if (layoutDefinition == null) return this.WrapPanelLayuot(finalSize, false); + return this.CustomLayout(layoutDefinition, finalSize, false, false); + } + + + #region Wrap Panel Layout + + /// + /// Unified method for wrap panel logic + /// + /// Available or final size + /// Pass true if measure required; pass false if arrange required + /// Final size + Size WrapPanelLayuot(Size availableSize, bool measure) + { + bool arrange = !measure; + double availableHeight = double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height; + + double currentheight = 0; + double columnWidth = 0; + + double resultWidth = 0; + double resultHeight = 0; + + Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); + foreach (FrameworkElement child in this.children) + { + // Measuring + if (measure) child.Measure(infinity); + + if (currentheight + child.DesiredSize.Height > availableHeight) + { + // Move to the next column + resultHeight = Math.Max(resultHeight, currentheight); + resultWidth += columnWidth; + currentheight = 0; + columnWidth = 0; + } + + // Arranging + if (arrange) child.Arrange(new Rect( + resultWidth, + currentheight, + child.DesiredSize.Width, + child.DesiredSize.Height)); + + columnWidth = Math.Max(columnWidth, child.DesiredSize.Width); + currentheight += child.DesiredSize.Height; + } + + return new Size(resultWidth + columnWidth, resultHeight); + } + + #endregion + + #region Control and Group Creation from a Definition + + FrameworkElement GetControl(RibbonToolBarControlDefinition controlDefinition) + { + string name = controlDefinition.Target; + return this.Children.FirstOrDefault(x => x.Name == name); + } + + Dictionary cachedControlGroups = new Dictionary(); + RibbonToolBarControlGroup GetControlGroup(RibbonToolBarControlGroupDefinition controlGroupDefinition) + { + RibbonToolBarControlGroup controlGroup = null; + if (!this.cachedControlGroups.TryGetValue(controlGroupDefinition, out controlGroup)) + { + controlGroup = new RibbonToolBarControlGroup(); + // Add items to the group + foreach (RibbonToolBarControlDefinition child in controlGroupDefinition.Children) + { + controlGroup.Items.Add(this.GetControl(child)); + } + this.cachedControlGroups.Add(controlGroupDefinition, controlGroup); + } + return controlGroup; + } + + #endregion + + #region Custom Layout + + // Cached separators (clear & set in Measure pass) + Dictionary separatorCache = new Dictionary(); + + /// + /// Layout logic for the given layout definition + /// + /// Current layout definition + /// Available or final size + /// Pass true if measure required; pass false if arrange required + /// Determines whether we have to add children to the logical and visual tree + /// Final size + Size CustomLayout(RibbonToolBarLayoutDefinition layoutDefinition, Size availableSize, bool measure, bool addchildren) + { + bool arrange = !measure; + double availableHeight = double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height; + + // Clear separator cahce + if (addchildren) + this.separatorCache.Clear(); + + // Get the first control and measure, its height accepts as row height + double rowHeight = this.GetRowHeight(layoutDefinition); + + + // Calculate whitespace + int rowCountInColumn = Math.Min(layoutDefinition.RowCount, layoutDefinition.Rows.Count); + double whitespace = (availableHeight - ((double)rowCountInColumn * rowHeight)) / (double)(rowCountInColumn + 1); + + double y = 0; + double x = 0; + double currentRowBegin = 0; + double currentMaxX = 0; + double maxy = 0; + for(int rowIndex = 0; rowIndex < layoutDefinition.Rows.Count; rowIndex++) + { + RibbonToolBarRow row = layoutDefinition.Rows[rowIndex]; + + x = currentRowBegin; + + if (rowIndex % rowCountInColumn == 0) + { + // Reset vars at new column + x = currentRowBegin = currentMaxX; + y = 0; + + if (rowIndex != 0) + { + #region Add separator + + Separator separator = null; + if (!this.separatorCache.TryGetValue(rowIndex, out separator)) + { + separator = new Separator(); + separator.Style = this.SeparatorStyle; + this.separatorCache.Add(rowIndex, separator); + } + if (measure) + { + separator.Height = availableHeight - separator.Margin.Bottom - separator.Margin.Top; + separator.Measure(availableSize); + } + if (arrange) separator.Arrange(new Rect(x, y, + separator.DesiredSize.Width, + separator.DesiredSize.Height)); + x += separator.DesiredSize.Width; + + if (addchildren) + { + // Add control in the children + this.AddVisualChild(separator); + this.AddLogicalChild(separator); + this.actualChildren.Add(separator); + } + + #endregion + } + } + y += whitespace; + + + // Measure & arrange new row + for(int i = 0; i < row.Children.Count; i++) + { + if (row.Children[i] is RibbonToolBarControlDefinition) + { + // Control Definition Case + RibbonToolBarControlDefinition controlDefinition = + (RibbonToolBarControlDefinition) row.Children[i]; + FrameworkElement control = this.GetControl(controlDefinition); + if (control == null) continue; + + if (addchildren) + { + // Add control in the children + this.AddVisualChild(control); + this.AddLogicalChild(control); + this.actualChildren.Add(control); + } + + if (measure) + { + // Apply Control Definition Properties + RibbonProperties.SetSize(control, RibbonProperties.GetSize(controlDefinition)); + control.Width = controlDefinition.Width; + control.Measure(availableSize); + } + if (arrange) + { + control.Arrange(new Rect(x, y, + control.DesiredSize.Width, + control.DesiredSize.Height)); + } + + x += control.DesiredSize.Width; + } + if (row.Children[i] is RibbonToolBarControlGroupDefinition) + { + // Control Definition Case + RibbonToolBarControlGroupDefinition controlGroupDefinition = + (RibbonToolBarControlGroupDefinition)row.Children[i]; + + RibbonToolBarControlGroup control = this.GetControlGroup(controlGroupDefinition); + + if (addchildren) + { + // Add control in the children + this.AddVisualChild(control); + this.AddLogicalChild(control); + this.actualChildren.Add(control); + } + + if (measure) + { + // Apply Control Definition Properties + control.IsFirstInRow = (i == 0); + control.IsLastInRow = (i == row.Children.Count - 1); + control.Measure(availableSize); + } + if (arrange) + { + control.Arrange(new Rect(x, y, + control.DesiredSize.Width, + control.DesiredSize.Height)); + } + + x += control.DesiredSize.Width; + } + } + + y += rowHeight; + if (currentMaxX < x) currentMaxX = x; + if (maxy < y) maxy = y; + } + + return new Size(currentMaxX, maxy + whitespace); + } + + // Get the first control and measure, its height accepts as row height + double GetRowHeight(RibbonToolBarLayoutDefinition layoutDefinition) + { + const double defaultRowHeight = 0; + foreach (RibbonToolBarRow row in layoutDefinition.Rows) + { + foreach (DependencyObject item in row.Children) + { + RibbonToolBarControlDefinition controlDefinition = item as RibbonToolBarControlDefinition; + RibbonToolBarControlGroupDefinition controlGroupDefinition = item as RibbonToolBarControlGroupDefinition; + FrameworkElement control = null; + if (controlDefinition != null) control = this.GetControl(controlDefinition); + else if (controlGroupDefinition != null) + control = this.GetControlGroup(controlGroupDefinition); + + if (control == null) return defaultRowHeight; + control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + return control.DesiredSize.Height; + } + } + return defaultRowHeight; + } + + #endregion + + #endregion + + #region QAT Support + + // (!) RibbonToolBar must not to be in QAT + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + return new Control(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonToolBarControlDefinition.cs b/Fluent.Ribbon/Controls/RibbonToolBarControlDefinition.cs similarity index 97% rename from Fluent/Controls/RibbonToolBarControlDefinition.cs rename to Fluent.Ribbon/Controls/RibbonToolBarControlDefinition.cs index ed5bcf7a2..5859aa2b0 100644 --- a/Fluent/Controls/RibbonToolBarControlDefinition.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBarControlDefinition.cs @@ -1,142 +1,142 @@ -using System; -using System.ComponentModel; -using System.Windows; - -namespace Fluent -{ - using Fluent.Extensibility; - - /// - /// Represent logical definition for a control in toolbar - /// - public class RibbonToolBarControlDefinition : DependencyObject, INotifyPropertyChanged, IRibbonSizeChangedSink - { - /// - /// Creates a new instance - /// - public RibbonToolBarControlDefinition() - { - RibbonProperties.SetSize(this, RibbonControlSize.Small); - } - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonToolBarControlDefinition)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonToolBarControlDefinition)); - - #endregion - - #region Target Property - - /// - /// Gets or sets name of the target control - /// - public string Target - { - get { return (string)this.GetValue(TargetProperty); } - set { this.SetValue(TargetProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ControlName. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TargetProperty = - DependencyProperty.Register("Target", typeof(string), - typeof(RibbonToolBarControlDefinition), new UIPropertyMetadata(null, OnTargetPropertyChanged)); - - static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonToolBarControlDefinition definition = (RibbonToolBarControlDefinition) d; - definition.Invalidate("Target"); - } - - #endregion - - #region Width Property - - /// - /// Gets or sets width of the target control - /// - public double Width - { - get { return (double)this.GetValue(WidthProperty); } - set { this.SetValue(WidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Width. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty WidthProperty = - DependencyProperty.Register("Width", typeof(double), typeof(RibbonToolBarControlDefinition), new UIPropertyMetadata(double.NaN, OnWidthPropertyChanged)); - - static void OnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonToolBarControlDefinition definition = (RibbonToolBarControlDefinition) d; - definition.Invalidate("Width"); - } - - #endregion - - #region Invalidating - - /// - /// Occurs when a property value changes. - /// - public event PropertyChangedEventHandler PropertyChanged; - - private void Invalidate(string propertyName) - { - if (this.PropertyChanged != null) - this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - - #region Implementation of IRibbonSizeChangedSink - - /// - /// Called when the size is changed - /// - /// Size before change - /// Size after change - public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) - { - this.Invalidate("Size"); - } - - #endregion - } +using System; +using System.ComponentModel; +using System.Windows; + +namespace Fluent +{ + using Fluent.Extensibility; + + /// + /// Represent logical definition for a control in toolbar + /// + public class RibbonToolBarControlDefinition : DependencyObject, INotifyPropertyChanged, IRibbonSizeChangedSink + { + /// + /// Creates a new instance + /// + public RibbonToolBarControlDefinition() + { + RibbonProperties.SetSize(this, RibbonControlSize.Small); + } + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonToolBarControlDefinition)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonToolBarControlDefinition)); + + #endregion + + #region Target Property + + /// + /// Gets or sets name of the target control + /// + public string Target + { + get { return (string)this.GetValue(TargetProperty); } + set { this.SetValue(TargetProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ControlName. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TargetProperty = + DependencyProperty.Register("Target", typeof(string), + typeof(RibbonToolBarControlDefinition), new UIPropertyMetadata(null, OnTargetPropertyChanged)); + + static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonToolBarControlDefinition definition = (RibbonToolBarControlDefinition) d; + definition.Invalidate("Target"); + } + + #endregion + + #region Width Property + + /// + /// Gets or sets width of the target control + /// + public double Width + { + get { return (double)this.GetValue(WidthProperty); } + set { this.SetValue(WidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Width. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty WidthProperty = + DependencyProperty.Register("Width", typeof(double), typeof(RibbonToolBarControlDefinition), new UIPropertyMetadata(double.NaN, OnWidthPropertyChanged)); + + static void OnWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonToolBarControlDefinition definition = (RibbonToolBarControlDefinition) d; + definition.Invalidate("Width"); + } + + #endregion + + #region Invalidating + + /// + /// Occurs when a property value changes. + /// + public event PropertyChangedEventHandler PropertyChanged; + + private void Invalidate(string propertyName) + { + if (this.PropertyChanged != null) + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region Implementation of IRibbonSizeChangedSink + + /// + /// Called when the size is changed + /// + /// Size before change + /// Size after change + public void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current) + { + this.Invalidate("Size"); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonToolBarControlGroup.cs b/Fluent.Ribbon/Controls/RibbonToolBarControlGroup.cs similarity index 97% rename from Fluent/Controls/RibbonToolBarControlGroup.cs rename to Fluent.Ribbon/Controls/RibbonToolBarControlGroup.cs index a298729a8..7f10e7b9f 100644 --- a/Fluent/Controls/RibbonToolBarControlGroup.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBarControlGroup.cs @@ -1,76 +1,76 @@ -using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represent logical container for toolbar items - /// - [ContentProperty("Children")] - public class RibbonToolBarControlGroup : ItemsControl - { - #region Properties - - /// - /// Gets whether the group is the fisrt control in the row - /// - public bool IsFirstInRow - { - get { return (bool)this.GetValue(IsFirstInRowProperty); } - set { this.SetValue(IsFirstInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsFirstInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsFirstInRowProperty = - DependencyProperty.Register("IsFirstInRow", typeof(bool), typeof(RibbonToolBarControlGroup), new UIPropertyMetadata(true)); - - /// - /// Gets whether the group is the last control in the row - /// - public bool IsLastInRow - { - get { return (bool)this.GetValue(IsLastInRowProperty); } - set { this.SetValue(IsLastInRowProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsFirstInRow. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsLastInRowProperty = - DependencyProperty.Register("IsLastInRow", typeof(bool), typeof(RibbonToolBarControlGroup), new UIPropertyMetadata(true)); - - #endregion - - #region Initialization - - [SuppressMessage("Microsoft.Performance", "CA1810")] - static RibbonToolBarControlGroup() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonToolBarControlGroup), new FrameworkPropertyMetadata(typeof(RibbonToolBarControlGroup))); - StyleProperty.OverrideMetadata(typeof(RibbonToolBarControlGroup), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonToolBarControlGroup)); - } - - return basevalue; - } - - #endregion - } +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represent logical container for toolbar items + /// + [ContentProperty("Children")] + public class RibbonToolBarControlGroup : ItemsControl + { + #region Properties + + /// + /// Gets whether the group is the fisrt control in the row + /// + public bool IsFirstInRow + { + get { return (bool)this.GetValue(IsFirstInRowProperty); } + set { this.SetValue(IsFirstInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsFirstInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsFirstInRowProperty = + DependencyProperty.Register("IsFirstInRow", typeof(bool), typeof(RibbonToolBarControlGroup), new UIPropertyMetadata(true)); + + /// + /// Gets whether the group is the last control in the row + /// + public bool IsLastInRow + { + get { return (bool)this.GetValue(IsLastInRowProperty); } + set { this.SetValue(IsLastInRowProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsFirstInRow. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsLastInRowProperty = + DependencyProperty.Register("IsLastInRow", typeof(bool), typeof(RibbonToolBarControlGroup), new UIPropertyMetadata(true)); + + #endregion + + #region Initialization + + [SuppressMessage("Microsoft.Performance", "CA1810")] + static RibbonToolBarControlGroup() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonToolBarControlGroup), new FrameworkPropertyMetadata(typeof(RibbonToolBarControlGroup))); + StyleProperty.OverrideMetadata(typeof(RibbonToolBarControlGroup), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(RibbonToolBarControlGroup)); + } + + return basevalue; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonToolBarControlGroupDefinition.cs b/Fluent.Ribbon/Controls/RibbonToolBarControlGroupDefinition.cs similarity index 96% rename from Fluent/Controls/RibbonToolBarControlGroupDefinition.cs rename to Fluent.Ribbon/Controls/RibbonToolBarControlGroupDefinition.cs index 797b91069..174a3ade2 100644 --- a/Fluent/Controls/RibbonToolBarControlGroupDefinition.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBarControlGroupDefinition.cs @@ -1,63 +1,63 @@ -using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Windows; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represent logical container for toolbar items - /// - [ContentProperty("Children")] - public class RibbonToolBarControlGroupDefinition : DependencyObject - { - #region Events - - /// - /// Occures when children has been changed - /// - public event NotifyCollectionChangedEventHandler ChildrenChanged; - - #endregion - - #region Fields - - // User defined rows - readonly ObservableCollection children = new ObservableCollection(); - - #endregion - - #region Children Property - - /// - /// Gets rows - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ObservableCollection Children - { - get { return this.children; } - } - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonToolBarControlGroupDefinition() - { - this.children.CollectionChanged += this.OnChildrenCollectionChanged; - } - - void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (this.ChildrenChanged != null) - this.ChildrenChanged(sender, e); - } - - #endregion - } +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Windows; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represent logical container for toolbar items + /// + [ContentProperty("Children")] + public class RibbonToolBarControlGroupDefinition : DependencyObject + { + #region Events + + /// + /// Occures when children has been changed + /// + public event NotifyCollectionChangedEventHandler ChildrenChanged; + + #endregion + + #region Fields + + // User defined rows + readonly ObservableCollection children = new ObservableCollection(); + + #endregion + + #region Children Property + + /// + /// Gets rows + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ObservableCollection Children + { + get { return this.children; } + } + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public RibbonToolBarControlGroupDefinition() + { + this.children.CollectionChanged += this.OnChildrenCollectionChanged; + } + + void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (this.ChildrenChanged != null) + this.ChildrenChanged(sender, e); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/RibbonToolBarLayoutDefinition.cs b/Fluent.Ribbon/Controls/RibbonToolBarLayoutDefinition.cs similarity index 96% rename from Fluent/Controls/RibbonToolBarLayoutDefinition.cs rename to Fluent.Ribbon/Controls/RibbonToolBarLayoutDefinition.cs index cd4b01556..97851dbbd 100644 --- a/Fluent/Controls/RibbonToolBarLayoutDefinition.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBarLayoutDefinition.cs @@ -1,94 +1,94 @@ -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Windows; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represents size definition for group box - /// - [ContentProperty("Rows")] - public class RibbonToolBarLayoutDefinition : DependencyObject - { - #region Fields - - // User defined rows - ObservableCollection rows = new ObservableCollection(); - - #endregion - - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonToolBarLayoutDefinition)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonToolBarLayoutDefinition)); - - #endregion - - #region Row Count - - /// - /// Gets or sets count of rows in the ribbon toolbar - /// - public int RowCount - { - get { return (int)this.GetValue(RowCountProperty); } - set { this.SetValue(RowCountProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for RowCount. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty RowCountProperty = - DependencyProperty.Register("RowCount", typeof(int), typeof(RibbonToolBar), new UIPropertyMetadata(3)); - - - #endregion - - - /// - /// Gets rows - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ObservableCollection Rows - { - get { return this.rows; } - } - - #endregion - } -} +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Windows; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents size definition for group box + /// + [ContentProperty("Rows")] + public class RibbonToolBarLayoutDefinition : DependencyObject + { + #region Fields + + // User defined rows + ObservableCollection rows = new ObservableCollection(); + + #endregion + + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(RibbonToolBarLayoutDefinition)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(RibbonToolBarLayoutDefinition)); + + #endregion + + #region Row Count + + /// + /// Gets or sets count of rows in the ribbon toolbar + /// + public int RowCount + { + get { return (int)this.GetValue(RowCountProperty); } + set { this.SetValue(RowCountProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for RowCount. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty RowCountProperty = + DependencyProperty.Register("RowCount", typeof(int), typeof(RibbonToolBar), new UIPropertyMetadata(3)); + + + #endregion + + + /// + /// Gets rows + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ObservableCollection Rows + { + get { return this.rows; } + } + + #endregion + } +} diff --git a/Fluent/Controls/RibbonToolBarRow.cs b/Fluent.Ribbon/Controls/RibbonToolBarRow.cs similarity index 96% rename from Fluent/Controls/RibbonToolBarRow.cs rename to Fluent.Ribbon/Controls/RibbonToolBarRow.cs index 0466af7f7..94890508c 100644 --- a/Fluent/Controls/RibbonToolBarRow.cs +++ b/Fluent.Ribbon/Controls/RibbonToolBarRow.cs @@ -1,46 +1,46 @@ -using System; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represents size definition for group box - /// - [ContentProperty("Children")] - [SuppressMessage("Microsoft.Naming", "CA1702", Justification = "We mean here 'bar row' instead of 'barrow'")] - public class RibbonToolBarRow : DependencyObject - { - #region Fields - - // User defined rows - readonly ObservableCollection children = new ObservableCollection(); - - #endregion - - #region Properties - - /// - /// Gets rows - /// - [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] - public ObservableCollection Children - { - get { return this.children; } - } - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonToolBarRow(){} - - #endregion - } -} +using System; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents size definition for group box + /// + [ContentProperty("Children")] + [SuppressMessage("Microsoft.Naming", "CA1702", Justification = "We mean here 'bar row' instead of 'barrow'")] + public class RibbonToolBarRow : DependencyObject + { + #region Fields + + // User defined rows + readonly ObservableCollection children = new ObservableCollection(); + + #endregion + + #region Properties + + /// + /// Gets rows + /// + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ObservableCollection Children + { + get { return this.children; } + } + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public RibbonToolBarRow(){} + + #endregion + } +} diff --git a/Fluent/Controls/RibbonWindow.cs b/Fluent.Ribbon/Controls/RibbonWindow.cs similarity index 61% rename from Fluent/Controls/RibbonWindow.cs rename to Fluent.Ribbon/Controls/RibbonWindow.cs index b26b17779..d4037a5f4 100644 --- a/Fluent/Controls/RibbonWindow.cs +++ b/Fluent.Ribbon/Controls/RibbonWindow.cs @@ -1,468 +1,378 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.Windows; - using System.Windows.Input; - using System.Windows.Interop; - using Fluent.Extensions; - using Fluent.Internal; - using Fluent.Metro.Native; -#if NET40 - using Microsoft.Windows.Shell; -#else - using System.Windows.Shell; -#endif - - /// - /// Represents basic window for ribbon - /// - [SuppressMessage("Microsoft.Design", "CA1049")] - [TemplatePart(Name = PART_Icon, Type = typeof(UIElement))] - [TemplatePart(Name = PART_ContentPresenter, Type = typeof(UIElement))] - [TemplatePart(Name = PART_WindowCommands, Type = typeof(WindowCommands))] - public class RibbonWindow : Window - { - private const string PART_Icon = "PART_Icon"; - private const string PART_ContentPresenter = "PART_ContentPresenter"; - private const string PART_WindowCommands = "PART_WindowCommands"; - - private FrameworkElement iconImage; - - #region Properties - - /// - /// Using a DependencyProperty as the backing store for WindowCommands. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty WindowCommandsProperty = DependencyProperty.Register("WindowCommands", typeof(WindowCommands), typeof(RibbonWindow), new PropertyMetadata(null)); - - /// - /// Gets or sets the window commands - /// - public WindowCommands WindowCommands - { - get { return (WindowCommands)this.GetValue(WindowCommandsProperty); } - set { this.SetValue(WindowCommandsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SaveWindowPosition. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SavePositionProperty = DependencyProperty.Register("SaveWindowPosition", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(false)); - - /// - /// Gets or sets whether window position will be saved and loaded. - /// - public bool SaveWindowPosition - { - get { return (bool)this.GetValue(SavePositionProperty); } - set { this.SetValue(SavePositionProperty, value); } - } - - /// - /// Gets or sets resize border thickness - /// - public Thickness ResizeBorderThickness - { - get { return (Thickness)this.GetValue(ResizeBorderThicknessProperty); } - set { this.SetValue(ResizeBorderThicknessProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeBorderTickness. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeBorderThicknessProperty = - DependencyProperty.Register("ResizeBorderThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(new Thickness(8), OnWindowChromeRelevantPropertyChanged)); - - /// - /// Gets or sets glass border thickness - /// - public Thickness GlassBorderThickness - { - get { return (Thickness)this.GetValue(GlassBorderThicknessProperty); } - set { this.SetValue(GlassBorderThicknessProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GlassBorderThickness. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GlassBorderThicknessProperty = - DependencyProperty.Register("GlassBorderThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(new Thickness(8, 50, 8, 8), OnWindowChromeRelevantPropertyChanged)); - - /// - /// Gets or sets corner radius - /// - public CornerRadius CornerRadius - { - get { return (CornerRadius)this.GetValue(CornerRadiusProperty); } - set { this.SetValue(CornerRadiusProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CornerRadiusProperty = - DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(RibbonWindow), new UIPropertyMetadata(new CornerRadius(15), OnWindowChromeRelevantPropertyChanged)); - - /// - /// Using a DependencyProperty as the backing store for DontUseDwm. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DontUseDwmProperty = - DependencyProperty.Register("DontUseDwm", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(false, OnDontUseDwmChanged)); - - /// - /// Gets or sets whether DWM should be used. - /// - public bool DontUseDwm - { - get { return (bool)this.GetValue(DontUseDwmProperty); } - set { this.SetValue(DontUseDwmProperty, value); } - } - - /// - /// Gets wheter DWM can be used ( is true and is false). - /// - public bool CanUseDwm - { - get { return (bool)this.GetValue(CanUseDwmProperty); } - private set { this.SetValue(CanUseDwmPropertyKey, value); } - } - - private static readonly DependencyPropertyKey CanUseDwmPropertyKey = DependencyProperty.RegisterReadOnly("CanUseDwm", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(true)); - - /// - /// Using a DependencyProperty as the backing store for CanUseDwm. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanUseDwmProperty = CanUseDwmPropertyKey.DependencyProperty; - - /// - /// Gets or sets whether icon is visible - /// - public bool IsIconVisible - { - get { return (bool)this.GetValue(IsIconVisibleProperty); } - set { this.SetValue(IsIconVisibleProperty, value); } - } - - /// - /// Gets or sets whether icon is visible - /// - public static readonly DependencyProperty IsIconVisibleProperty = DependencyProperty.Register("IsIconVisible", typeof(bool), typeof(RibbonWindow), new UIPropertyMetadata(true)); - - // todo check if IsCollapsed and IsAutomaticCollapseEnabled should be reduced to one shared property for RibbonWindow and Ribbon - /// - /// Gets whether window is collapsed - /// - public bool IsCollapsed - { - get { return (bool)this.GetValue(IsCollapsedProperty); } - set { this.SetValue(IsCollapsedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsCollapsed. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCollapsedProperty = - DependencyProperty.Register("IsCollapsed", typeof(bool), - typeof(RibbonWindow), new FrameworkPropertyMetadata(false)); - - /// - /// Defines if the Ribbon should automatically set when the width or height of the owner window drop under or - /// - public bool IsAutomaticCollapseEnabled - { - get { return (bool)this.GetValue(IsAutomaticCollapseEnabledProperty); } - set { this.SetValue(IsAutomaticCollapseEnabledProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsCollapsed. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsAutomaticCollapseEnabledProperty = - DependencyProperty.Register("IsAutomaticCollapseEnabled", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(true)); - - private readonly WindowSizing windowSizing; - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - static RibbonWindow() - { - StyleProperty.OverrideMetadata(typeof(RibbonWindow), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonWindow), new FrameworkPropertyMetadata(typeof(RibbonWindow))); - - RibbonProperties.TitleBarHeightProperty.OverrideMetadata(typeof(RibbonWindow), new FrameworkPropertyMetadata(OnWindowChromeRelevantPropertyChanged)); - } - - // Coerce object style - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue != null) - { - return basevalue; - } - - var frameworkElement = d as FrameworkElement; - if (frameworkElement != null) - { - basevalue = frameworkElement.TryFindResource(typeof(RibbonWindow)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public RibbonWindow() - { - this.SizeChanged += this.OnSizeChanged; - - this.windowSizing = new WindowSizing(this); - } - - #endregion - - #region Overrides - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnSourceInitialized(EventArgs e) - { - base.OnSourceInitialized(e); - - this.UpdateCanUseDwm(); - - this.UpdateWindowChrome(); - - this.windowSizing.WindowInitialized(); - } - - /// - /// Called when the property changes. - /// - /// A reference to the root of the old content tree.A reference to the root of the new content tree. - protected override void OnContentChanged(object oldContent, object newContent) - { - base.OnContentChanged(oldContent, newContent); - - var content = newContent as IInputElement; - - if (content != null) - { - WindowChrome.SetIsHitTestVisibleInChrome(content, true); - } - } - - #endregion - - private static void OnWindowChromeRelevantPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var window = d as RibbonWindow; - - if (window == null) - { - return; - } - - window.UpdateWindowChrome(); - } - - private static void OnDontUseDwmChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var window = d as RibbonWindow; - - if (window == null) - { - return; - } - - window.UpdateCanUseDwm(); - } - - // Size change to collapse ribbon - private void OnSizeChanged(object sender, SizeChangedEventArgs e) - { - this.MaintainIsCollapsed(); - } - - private void MaintainIsCollapsed() - { - if (this.IsAutomaticCollapseEnabled == false) - { - return; - } - - if (this.ActualWidth < Ribbon.MinimalVisibleWidth - || this.ActualHeight < Ribbon.MinimalVisibleHeight) - { - this.IsCollapsed = true; - } - else - { - this.IsCollapsed = false; - } - } - - private void UpdateWindowChrome() - { - var windowChrome = WindowChrome.GetWindowChrome(this); - - if (windowChrome == null) - { - windowChrome = new WindowChrome(); - WindowChrome.SetWindowChrome(this, windowChrome); - } - - windowChrome.CaptionHeight = RibbonProperties.GetTitleBarHeight(this); - windowChrome.CornerRadius = this.CornerRadius; - windowChrome.GlassFrameThickness = this.GlassBorderThickness; - windowChrome.ResizeBorderThickness = this.ResizeBorderThickness; -#if NET45 - windowChrome.UseAeroCaptionButtons = this.CanUseDwm; -#endif - } - - private void UpdateCanUseDwm() - { - this.CanUseDwm = NativeMethods.IsDwmEnabled() - && this.DontUseDwm == false; - } - - #region Metro - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - this.UpdateCanUseDwm(); - - if (this.iconImage != null) - { - this.iconImage.MouseDown -= this.HandleIconMouseDown; - } - - if (this.WindowCommands == null) - { - this.WindowCommands = new WindowCommands(); - } - - this.iconImage = this.GetTemplateChild(PART_Icon) as FrameworkElement; - - if (this.iconImage != null) - { - WindowChrome.SetIsHitTestVisibleInChrome(this.iconImage, true); - - this.iconImage.MouseDown += this.HandleIconMouseDown; - } - - var partContentPresenter = this.GetTemplateChild(PART_ContentPresenter) as UIElement; - - if (partContentPresenter != null) - { - WindowChrome.SetIsHitTestVisibleInChrome(partContentPresenter, true); - } - - var partWindowCommands = this.GetTemplateChild(PART_WindowCommands) as UIElement; - - if (partWindowCommands != null) - { - WindowChrome.SetIsHitTestVisibleInChrome(partWindowCommands, true); - } - - // This has to be done when the theme is changed. Otherwise maximized windows have the wrong size. - if (this.WindowState == WindowState.Maximized) - { - this.WindowState = WindowState.Normal; - this.WindowState = WindowState.Maximized; - } - } - - /// - /// Raises the event. - /// - /// An that contains the event data. - protected override void OnStateChanged(EventArgs e) - { - if (this.WindowCommands != null) - { - this.WindowCommands.RefreshMaximizeIconState(); - } - - base.OnStateChanged(e); - } - - private void HandleIconMouseDown(object sender, MouseButtonEventArgs e) - { - if (e.ChangedButton == MouseButton.Left) - { - if (e.ClickCount == 1) - { - e.Handled = true; - - ShowSystemMenuPhysicalCoordinates(this, this.PointToScreen(new Point(0, RibbonProperties.GetTitleBarHeight(this)))); - } - else if (e.ClickCount == 2) - { - e.Handled = true; - - this.Close(); - } - } - else if (e.ChangedButton == MouseButton.Right) - { - e.Handled = true; - - this.RunInDispatcherAsync(() => - { - var mousePosition = e.GetPosition(this); - ShowSystemMenuPhysicalCoordinates(this, this.PointToScreen(mousePosition)); - }); - } - } - - private static void ShowSystemMenuPhysicalCoordinates(Window window, Point physicalScreenLocation) - { - if (window == null) - { - return; - } - - var hwnd = new WindowInteropHelper(window).Handle; - if (hwnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(hwnd)) - { - return; - } - - var hmenu = UnsafeNativeMethods.GetSystemMenu(hwnd, false); - - var cmd = UnsafeNativeMethods.TrackPopupMenuEx(hmenu, Constants.TPM_LEFTBUTTON | Constants.TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero); - if (0 != cmd) - { - UnsafeNativeMethods.PostMessage(hwnd, Constants.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero); - } - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Interactivity; + using ControlzEx.Behaviors; + + using Fluent.Extensions; + using Fluent.Helpers; + + //using WindowChrome = System.Windows.Shell.WindowChrome; + using WindowChrome = ControlzEx.Microsoft.Windows.Shell.WindowChrome; + + /// + /// Represents basic window for ribbon + /// + [SuppressMessage("Microsoft.Design", "CA1049")] + [TemplatePart(Name = PART_Icon, Type = typeof(UIElement))] + [TemplatePart(Name = PART_ContentPresenter, Type = typeof(UIElement))] + [TemplatePart(Name = PART_WindowCommands, Type = typeof(WindowCommands))] + public class RibbonWindow : Window + { + private const string PART_Icon = "PART_Icon"; + private const string PART_ContentPresenter = "PART_ContentPresenter"; + private const string PART_WindowCommands = "PART_WindowCommands"; + + private FrameworkElement iconImage; + + #region Properties + + /// + /// Using a DependencyProperty as the backing store for WindowCommands. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty WindowCommandsProperty = DependencyProperty.Register("WindowCommands", typeof(WindowCommands), typeof(RibbonWindow), new PropertyMetadata(null)); + + /// + /// Gets or sets the window commands + /// + public WindowCommands WindowCommands + { + get { return (WindowCommands)this.GetValue(WindowCommandsProperty); } + set { this.SetValue(WindowCommandsProperty, value); } + } + + /// + /// Gets or sets resize border thickness + /// + public Thickness ResizeBorderThickness + { + get { return (Thickness)this.GetValue(ResizeBorderThicknessProperty); } + set { this.SetValue(ResizeBorderThicknessProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ResizeBorderTickness. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ResizeBorderThicknessProperty = + DependencyProperty.Register("ResizeBorderThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(new Thickness(8D))); + + /// + /// Gets or sets glass border thickness + /// + public Thickness GlassFrameThickness + { + get { return (Thickness)this.GetValue(GlassFrameThicknessProperty); } + set { this.SetValue(GlassFrameThicknessProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GlassFrameThickness. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GlassFrameThicknessProperty = + DependencyProperty.Register("GlassFrameThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(new Thickness(0D))); + + /// + /// Gets or sets corner radius + /// + public CornerRadius CornerRadius + { + get { return (CornerRadius)this.GetValue(CornerRadiusProperty); } + set { this.SetValue(CornerRadiusProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CornerRadius. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CornerRadiusProperty = + DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(RibbonWindow), new UIPropertyMetadata(new CornerRadius(0D))); + + /// + /// Using a DependencyProperty as the backing store for DontUseDwm. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DontUseDwmProperty = + DependencyProperty.Register("DontUseDwm", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(false, OnDontUseDwmChanged)); + + /// + /// Gets or sets whether DWM should be used. + /// + public bool DontUseDwm + { + get { return (bool)this.GetValue(DontUseDwmProperty); } + set { this.SetValue(DontUseDwmProperty, value); } + } + + /// + /// Gets wheter DWM can be used ( is true and is false). + /// + public bool CanUseDwm + { + get { return (bool)this.GetValue(CanUseDwmProperty); } + private set { this.SetValue(CanUseDwmPropertyKey, value); } + } + + private static readonly DependencyPropertyKey CanUseDwmPropertyKey = DependencyProperty.RegisterReadOnly("CanUseDwm", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(true)); + + /// + /// Using a DependencyProperty as the backing store for CanUseDwm. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanUseDwmProperty = CanUseDwmPropertyKey.DependencyProperty; + + /// + /// Defines if the default window buttons should be used + /// + public bool UseAeroCaptionButtons + { + get { return (bool)this.GetValue(UseAeroCaptionButtonsProperty); } + set { this.SetValue(UseAeroCaptionButtonsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for UseAeroCaptionButtons. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty UseAeroCaptionButtonsProperty = + DependencyProperty.Register("UseAeroCaptionButtons", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(true)); + + /// + /// Gets or sets whether icon is visible + /// + public bool IsIconVisible + { + get { return (bool)this.GetValue(IsIconVisibleProperty); } + set { this.SetValue(IsIconVisibleProperty, value); } + } + + /// + /// Gets or sets whether icon is visible + /// + public static readonly DependencyProperty IsIconVisibleProperty = DependencyProperty.Register("IsIconVisible", typeof(bool), typeof(RibbonWindow), new UIPropertyMetadata(true)); + + // todo check if IsCollapsed and IsAutomaticCollapseEnabled should be reduced to one shared property for RibbonWindow and Ribbon + /// + /// Gets whether window is collapsed + /// + public bool IsCollapsed + { + get { return (bool)this.GetValue(IsCollapsedProperty); } + set { this.SetValue(IsCollapsedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsCollapsed. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCollapsedProperty = + DependencyProperty.Register("IsCollapsed", typeof(bool), + typeof(RibbonWindow), new FrameworkPropertyMetadata(false)); + + /// + /// Defines if the Ribbon should automatically set when the width or height of the owner window drop under or + /// + public bool IsAutomaticCollapseEnabled + { + get { return (bool)this.GetValue(IsAutomaticCollapseEnabledProperty); } + set { this.SetValue(IsAutomaticCollapseEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsCollapsed. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsAutomaticCollapseEnabledProperty = + DependencyProperty.Register("IsAutomaticCollapseEnabled", typeof(bool), typeof(RibbonWindow), new PropertyMetadata(true)); + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + static RibbonWindow() + { + StyleProperty.OverrideMetadata(typeof(RibbonWindow), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + DefaultStyleKeyProperty.OverrideMetadata(typeof(RibbonWindow), new FrameworkPropertyMetadata(typeof(RibbonWindow))); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue != null) + { + return basevalue; + } + + var frameworkElement = d as FrameworkElement; + if (frameworkElement != null) + { + basevalue = frameworkElement.TryFindResource(typeof(RibbonWindow)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public RibbonWindow() + { + this.SizeChanged += this.OnSizeChanged; + + // WindowChrome initialization has to occur in constructor. Otherwise the load event is fired early. + this.InitializeWindowChromeBehavior(); + } + + #endregion + + #region Overrides + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + + this.UpdateCanUseDwm(); + } + + /// + /// Initializes the WindowChromeBehavior which is needed to render the custom WindowChrome + /// + private void InitializeWindowChromeBehavior() + { + var behavior = new WindowChromeBehavior(); + BindingOperations.SetBinding(behavior, WindowChromeBehavior.CaptionHeightProperty, new Binding { Path = new PropertyPath(RibbonProperties.TitleBarHeightProperty), Source = this }); + BindingOperations.SetBinding(behavior, WindowChromeBehavior.ResizeBorderThicknessProperty, new Binding { Path = new PropertyPath(ResizeBorderThicknessProperty), Source = this }); + BindingOperations.SetBinding(behavior, WindowChromeBehavior.CornerRadiusProperty, new Binding { Path = new PropertyPath(CornerRadiusProperty), Source = this }); + BindingOperations.SetBinding(behavior, WindowChromeBehavior.GlassFrameThicknessProperty, new Binding { Path = new PropertyPath(GlassFrameThicknessProperty), Source = this }); + BindingOperations.SetBinding(behavior, WindowChromeBehavior.UseAeroCaptionButtonsProperty, new Binding { Path = new PropertyPath(UseAeroCaptionButtonsProperty), Source = this }); + Interaction.GetBehaviors(this).Add(behavior); + } + + #endregion + + private static void OnDontUseDwmChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var window = d as RibbonWindow; + + window?.UpdateCanUseDwm(); + } + + // Size change to collapse ribbon + private void OnSizeChanged(object sender, SizeChangedEventArgs e) + { + this.MaintainIsCollapsed(); + } + + private void MaintainIsCollapsed() + { + if (this.IsAutomaticCollapseEnabled == false) + { + return; + } + + if (this.ActualWidth < Ribbon.MinimalVisibleWidth + || this.ActualHeight < Ribbon.MinimalVisibleHeight) + { + this.IsCollapsed = true; + } + else + { + this.IsCollapsed = false; + } + } + + private void UpdateCanUseDwm() + { + this.CanUseDwm = NativeMethods.IsDwmEnabled() + && this.DontUseDwm == false; + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + this.UpdateCanUseDwm(); + + if (this.iconImage != null) + { + this.iconImage.MouseDown -= this.HandleIconMouseDown; + } + + if (this.WindowCommands == null) + { + this.WindowCommands = new WindowCommands(); + } + + this.iconImage = this.GetPart(PART_Icon); + + if (this.iconImage != null) + { + this.iconImage.MouseDown += this.HandleIconMouseDown; + } + + this.GetPart(PART_Icon)?.SetValue(WindowChrome.IsHitTestVisibleInChromeProperty, true); + this.GetPart(PART_WindowCommands)?.SetValue(WindowChrome.IsHitTestVisibleInChromeProperty, true); + } + + /// + /// Raises the event. + /// + /// An that contains the event data. + protected override void OnStateChanged(EventArgs e) + { + this.WindowCommands?.RefreshMaximizeIconState(); + + base.OnStateChanged(e); + } + + private void HandleIconMouseDown(object sender, MouseButtonEventArgs e) + { + switch (e.ChangedButton) + { + case MouseButton.Left: + if (e.ClickCount == 1) + { + e.Handled = true; + + WindowSteeringHelper.ShowSystemMenuPhysicalCoordinates(this, e, this.PointToScreen(new Point(0, RibbonProperties.GetTitleBarHeight(this)))); + } + else if (e.ClickCount == 2) + { + e.Handled = true; + + this.Close(); + } + break; + + case MouseButton.Right: + e.Handled = true; + + this.RunInDispatcherAsync(() => + { + WindowSteeringHelper.ShowSystemMenuPhysicalCoordinates(this, e); + }); + break; + } + } + + /// + /// Gets the template child with the given name. + /// + /// The interface type inheirted from DependencyObject. + /// The name of the template child. + internal T GetPart(string name) + where T : DependencyObject + { + return this.GetTemplateChild(name) as T; + } + } } \ No newline at end of file diff --git a/Fluent/Controls/ScreenTip.cs b/Fluent.Ribbon/Controls/ScreenTip.cs similarity index 94% rename from Fluent/Controls/ScreenTip.cs rename to Fluent.Ribbon/Controls/ScreenTip.cs index c6ee5db82..99350bae6 100644 --- a/Fluent/Controls/ScreenTip.cs +++ b/Fluent.Ribbon/Controls/ScreenTip.cs @@ -1,438 +1,429 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.Windows; - using System.Windows.Media; - using System.Windows.Controls; - using System.Windows.Documents; - using System.Windows.Controls.Primitives; - using System.Windows.Input; - - /// - /// ScreenTips display the name of the control, - /// the keyboard shortcut for the control, and a brief description - /// of how to use the control. ScreenTips also can provide F1 support, - /// which opens help and takes the user directly to the related - /// help topic for the control whose ScreenTip was - /// displayed when the F1 button was pressed - /// - public class ScreenTip : ToolTip - { - #region Initialization - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static ScreenTip() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(ScreenTip), new FrameworkPropertyMetadata(typeof(ScreenTip))); - StyleProperty.OverrideMetadata(typeof(ScreenTip), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - } - - private static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - var frameworkElement = d as FrameworkElement; - if (frameworkElement != null) - { - basevalue = frameworkElement.TryFindResource(typeof(ScreenTip)); - } - } - - return basevalue; - } - - /// - /// Default constructor - /// - public ScreenTip() - { - this.Opened += this.OnToolTipOpened; - this.Closed += this.OnToolTipClosed; - this.CustomPopupPlacementCallback = this.CustomPopupPlacementMethod; - this.Placement = PlacementMode.Custom; - this.HelpLabelVisibility = Visibility.Visible; - } - - #endregion - - #region Popup Custom Placement - - // Calculate two variants: below and upper ribbon - CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupSize, Size targetSize, Point offset) - { - if (this.PlacementTarget == null) - { - return new CustomPopupPlacement[] { }; - } - - Ribbon ribbon = null; - UIElement topLevelElement = null; - FindControls(this.PlacementTarget, ref ribbon, ref topLevelElement); - - // Exclude QAT items - var notQuickAccessItem = !IsQuickAccessItem(this.PlacementTarget); - var notContextMenuChild = !IsContextMenuChild(this.PlacementTarget); - var rightToLeftOffset = this.FlowDirection == FlowDirection.RightToLeft - ? -popupSize.Width - : 0; - - var decoratorChild = GetDecoratorChild(topLevelElement); - - if (notQuickAccessItem - && this.IsRibbonAligned - && ribbon != null) - { - var belowY = ribbon.TranslatePoint(new Point(0, ribbon.ActualHeight), this.PlacementTarget).Y; - var aboveY = ribbon.TranslatePoint(new Point(0, 0), this.PlacementTarget).Y - popupSize.Height; - var below = new CustomPopupPlacement(new Point(rightToLeftOffset, belowY + 1), PopupPrimaryAxis.Horizontal); - var above = new CustomPopupPlacement(new Point(rightToLeftOffset, aboveY - 1), PopupPrimaryAxis.Horizontal); - return new[] { below, above }; - } - - if (notQuickAccessItem - && this.IsRibbonAligned - && notContextMenuChild - && topLevelElement is Window == false - && decoratorChild != null) - { - // Placed on Popup? - var belowY = decoratorChild.TranslatePoint(new Point(0, ((FrameworkElement)decoratorChild).ActualHeight), this.PlacementTarget).Y; - var aboveY = decoratorChild.TranslatePoint(new Point(0, 0), this.PlacementTarget).Y - popupSize.Height; - var below = new CustomPopupPlacement(new Point(rightToLeftOffset, belowY + 1), PopupPrimaryAxis.Horizontal); - var above = new CustomPopupPlacement(new Point(rightToLeftOffset, aboveY - 1), PopupPrimaryAxis.Horizontal); - return new[] { below, above }; - } - - return new[] { - new CustomPopupPlacement(new Point(rightToLeftOffset, this.PlacementTarget.RenderSize.Height + 1), PopupPrimaryAxis.Horizontal), - new CustomPopupPlacement(new Point(rightToLeftOffset, -popupSize.Height - 1), PopupPrimaryAxis.Horizontal)}; - } - - private static bool IsContextMenuChild(UIElement element) - { - do - { - var parent = VisualTreeHelper.GetParent(element) as UIElement; - //if (parent is ContextMenuBar) return true; - element = parent; - } while (element != null); - - return false; - } - - private static bool IsQuickAccessItem(UIElement element) - { - do - { - var parent = VisualTreeHelper.GetParent(element) as UIElement; - if (parent is QuickAccessToolBar) - { - return true; - } - - element = parent; - } - while (element != null); - - return false; - } - - private static UIElement GetDecoratorChild(UIElement popupRoot) - { - if (popupRoot == null) - { - return null; - } - - var decorator = popupRoot as AdornerDecorator; - if (decorator != null) - { - return decorator.Child; - } - - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(popupRoot); i++) - { - var element = GetDecoratorChild(VisualTreeHelper.GetChild(popupRoot, i) as UIElement); - if (element != null) - { - return element; - } - } - - return null; - } - - private static void FindControls(UIElement obj, ref Ribbon ribbon, ref UIElement topLevelElement) - { - if (obj == null) - { - return; - } - - var objRibbon = obj as Ribbon; - if (objRibbon != null) - { - ribbon = objRibbon; - } - - var parentVisual = VisualTreeHelper.GetParent(obj) as UIElement; - if (parentVisual == null) - { - topLevelElement = obj; - } - else - { - FindControls(parentVisual, ref ribbon, ref topLevelElement); - } - } - - #endregion - - #region Title Property - - /// - /// Gets or sets title of the screen tip - /// - [System.ComponentModel.DisplayName("Title"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Title of the screen tip")] - public string Title - { - get { return (string)this.GetValue(TitleProperty); } - set { this.SetValue(TitleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Title. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); - - #endregion - - #region Text Property - - /// - /// Gets or sets text of the screen tip - /// - [System.ComponentModel.DisplayName("Text"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Main text of the screen tip")] - public string Text - { - get { return (string)this.GetValue(TextProperty); } - set { this.SetValue(TextProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Text. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextProperty = - DependencyProperty.Register("Text", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); - - #endregion - - #region DisableReason Property - - /// - /// Gets or sets disable reason of the associated screen tip's control - /// - [System.ComponentModel.DisplayName("Disable Reason"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Describe here what would cause disable of the control")] - public string DisableReason - { - get { return (string)this.GetValue(DisableReasonProperty); } - set { this.SetValue(DisableReasonProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for DisableReason. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DisableReasonProperty = - DependencyProperty.Register("DisableReason", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); - - #endregion - - #region HelpTopic Property - - /// - /// Gets or sets help topic of the ScreenTip - /// - [System.ComponentModel.DisplayName("Help Topic"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Help topic (it will be used to execute help)")] - public object HelpTopic - { - get { return (object)this.GetValue(HelpTopicProperty); } - set { this.SetValue(HelpTopicProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HelpTopic. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HelpTopicProperty = - DependencyProperty.Register("HelpTopic", typeof(object), typeof(ScreenTip), new UIPropertyMetadata(null)); - - #endregion - - #region Image Property - - /// - /// Gets or sets image of the screen tip - /// - [System.ComponentModel.DisplayName("Image"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Image of the screen tip")] - public ImageSource Image - { - get { return (ImageSource)this.GetValue(ImageProperty); } - set { this.SetValue(ImageProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Image. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ImageProperty = - DependencyProperty.Register("Image", typeof(ImageSource), typeof(ScreenTip), new UIPropertyMetadata(null)); - - #endregion - - #region ShowHelp Property - /// - /// Shows or hides the Help Label - /// - [System.ComponentModel.DisplayName("HelpLabelVisibility"), - System.ComponentModel.Category("Screen Tip"), - System.ComponentModel.Description("Sets the visibility of the F1 Help Label")] - public Visibility HelpLabelVisibility - { - get { return (Visibility)this.GetValue(HelpLabelVisibilityProperty); } - set { this.SetValue(HelpLabelVisibilityProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store the boolean. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HelpLabelVisibilityProperty = - DependencyProperty.Register("HelpLabelVisibility", typeof(Visibility), typeof(ScreenTip), new UIPropertyMetadata(Visibility.Visible)); - #endregion - - #region Help Invocation - - /// - /// Occurs when user press F1 on ScreenTip with HelpTopic filled - /// - public static event EventHandler HelpPressed; - - #endregion - - #region IsRibbonAligned - - /// - /// Gets or set whether ScreenTip should positioned below Ribbon - /// - public bool IsRibbonAligned - { - get { return (bool)this.GetValue(IsRibbonAlignedProperty); } - set { this.SetValue(IsRibbonAlignedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for BelowRibbon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsRibbonAlignedProperty = - DependencyProperty.Register("BelowRibbon", typeof(bool), typeof(ScreenTip), - new UIPropertyMetadata(true)); - - - #endregion - - #region F1 Help Handling - - // Currently focused element - private IInputElement focusedElement; - - private void OnToolTipClosed(object sender, RoutedEventArgs e) - { - if (this.focusedElement == null) - { - return; - } - - this.focusedElement.PreviewKeyDown -= this.OnFocusedElementPreviewKeyDown; - this.focusedElement = null; - } - - private void OnToolTipOpened(object sender, RoutedEventArgs e) - { - if (this.HelpTopic == null) - { - return; - } - - this.focusedElement = Keyboard.FocusedElement; - if (this.focusedElement != null) - { - this.focusedElement.PreviewKeyDown += this.OnFocusedElementPreviewKeyDown; - } - } - - void OnFocusedElementPreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key != Key.F1) - { - return; - } - - e.Handled = true; - - if (HelpPressed != null) - { - HelpPressed(null, new ScreenTipHelpEventArgs(this.HelpTopic)); - } - } - - #endregion - } - - /// - /// Event args for HelpPressed event handler - /// - public class ScreenTipHelpEventArgs : EventArgs - { - /// - /// Gets help topic associated with screen tip - /// - public object HelpTopic { get; private set; } - - /// - /// Constructor - /// - /// Help topic - public ScreenTipHelpEventArgs(object helpTopic) - { - this.HelpTopic = helpTopic; - } - } +namespace Fluent +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Media; + using System.Windows.Controls; + using System.Windows.Documents; + using System.Windows.Controls.Primitives; + using System.Windows.Input; + + /// + /// ScreenTips display the name of the control, + /// the keyboard shortcut for the control, and a brief description + /// of how to use the control. ScreenTips also can provide F1 support, + /// which opens help and takes the user directly to the related + /// help topic for the control whose ScreenTip was + /// displayed when the F1 button was pressed + /// + public class ScreenTip : ToolTip + { + #region Initialization + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static ScreenTip() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ScreenTip), new FrameworkPropertyMetadata(typeof(ScreenTip))); + StyleProperty.OverrideMetadata(typeof(ScreenTip), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + var frameworkElement = d as FrameworkElement; + if (frameworkElement != null) + { + basevalue = frameworkElement.TryFindResource(typeof(ScreenTip)); + } + } + + return basevalue; + } + + /// + /// Default constructor + /// + public ScreenTip() + { + this.Opened += this.OnToolTipOpened; + this.Closed += this.OnToolTipClosed; + this.CustomPopupPlacementCallback = this.CustomPopupPlacementMethod; + this.Placement = PlacementMode.Custom; + this.HelpLabelVisibility = Visibility.Visible; + } + + #endregion + + #region Popup Custom Placement + + // Calculate two variants: below and upper ribbon + CustomPopupPlacement[] CustomPopupPlacementMethod(Size popupSize, Size targetSize, Point offset) + { + if (this.PlacementTarget == null) + { + return new CustomPopupPlacement[] { }; + } + + Ribbon ribbon = null; + UIElement topLevelElement = null; + FindControls(this.PlacementTarget, ref ribbon, ref topLevelElement); + + // Exclude QAT items + var notQuickAccessItem = !IsQuickAccessItem(this.PlacementTarget); + var notContextMenuChild = !IsContextMenuChild(this.PlacementTarget); + var rightToLeftOffset = this.FlowDirection == FlowDirection.RightToLeft + ? -popupSize.Width + : 0; + + var decoratorChild = GetDecoratorChild(topLevelElement); + + if (notQuickAccessItem + && this.IsRibbonAligned + && ribbon != null) + { + var belowY = ribbon.TranslatePoint(new Point(0, ribbon.ActualHeight), this.PlacementTarget).Y; + var aboveY = ribbon.TranslatePoint(new Point(0, 0), this.PlacementTarget).Y - popupSize.Height; + var below = new CustomPopupPlacement(new Point(rightToLeftOffset, belowY + 1), PopupPrimaryAxis.Horizontal); + var above = new CustomPopupPlacement(new Point(rightToLeftOffset, aboveY - 1), PopupPrimaryAxis.Horizontal); + return new[] { below, above }; + } + + if (notQuickAccessItem + && this.IsRibbonAligned + && notContextMenuChild + && topLevelElement is Window == false + && decoratorChild != null) + { + // Placed on Popup? + var belowY = decoratorChild.TranslatePoint(new Point(0, ((FrameworkElement)decoratorChild).ActualHeight), this.PlacementTarget).Y; + var aboveY = decoratorChild.TranslatePoint(new Point(0, 0), this.PlacementTarget).Y - popupSize.Height; + var below = new CustomPopupPlacement(new Point(rightToLeftOffset, belowY + 1), PopupPrimaryAxis.Horizontal); + var above = new CustomPopupPlacement(new Point(rightToLeftOffset, aboveY - 1), PopupPrimaryAxis.Horizontal); + return new[] { below, above }; + } + + return new[] { + new CustomPopupPlacement(new Point(rightToLeftOffset, this.PlacementTarget.RenderSize.Height + 1), PopupPrimaryAxis.Horizontal), + new CustomPopupPlacement(new Point(rightToLeftOffset, -popupSize.Height - 1), PopupPrimaryAxis.Horizontal)}; + } + + private static bool IsContextMenuChild(UIElement element) + { + do + { + var parent = VisualTreeHelper.GetParent(element) as UIElement; + //if (parent is ContextMenuBar) return true; + element = parent; + } while (element != null); + + return false; + } + + private static bool IsQuickAccessItem(UIElement element) + { + do + { + var parent = VisualTreeHelper.GetParent(element) as UIElement; + if (parent is QuickAccessToolBar) + { + return true; + } + + element = parent; + } + while (element != null); + + return false; + } + + private static UIElement GetDecoratorChild(UIElement popupRoot) + { + if (popupRoot == null) + { + return null; + } + + var decorator = popupRoot as AdornerDecorator; + if (decorator != null) + { + return decorator.Child; + } + + for (var i = 0; i < VisualTreeHelper.GetChildrenCount(popupRoot); i++) + { + var element = GetDecoratorChild(VisualTreeHelper.GetChild(popupRoot, i) as UIElement); + if (element != null) + { + return element; + } + } + + return null; + } + + private static void FindControls(UIElement obj, ref Ribbon ribbon, ref UIElement topLevelElement) + { + if (obj == null) + { + return; + } + + var objRibbon = obj as Ribbon; + if (objRibbon != null) + { + ribbon = objRibbon; + } + + var parentVisual = VisualTreeHelper.GetParent(obj) as UIElement; + if (parentVisual == null) + { + topLevelElement = obj; + } + else + { + FindControls(parentVisual, ref ribbon, ref topLevelElement); + } + } + + #endregion + + #region Title Property + + /// + /// Gets or sets title of the screen tip + /// + [System.ComponentModel.DisplayName("Title"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Title of the screen tip")] + public string Title + { + get { return (string)this.GetValue(TitleProperty); } + set { this.SetValue(TitleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Title. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); + + #endregion + + #region Text Property + + /// + /// Gets or sets text of the screen tip + /// + [System.ComponentModel.DisplayName("Text"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Main text of the screen tip")] + public string Text + { + get { return (string)this.GetValue(TextProperty); } + set { this.SetValue(TextProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Text. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); + + #endregion + + #region DisableReason Property + + /// + /// Gets or sets disable reason of the associated screen tip's control + /// + [System.ComponentModel.DisplayName("Disable Reason"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Describe here what would cause disable of the control")] + public string DisableReason + { + get { return (string)this.GetValue(DisableReasonProperty); } + set { this.SetValue(DisableReasonProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for DisableReason. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DisableReasonProperty = + DependencyProperty.Register("DisableReason", typeof(string), typeof(ScreenTip), new UIPropertyMetadata("")); + + #endregion + + #region HelpTopic Property + + /// + /// Gets or sets help topic of the ScreenTip + /// + [System.ComponentModel.DisplayName("Help Topic"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Help topic (it will be used to execute help)")] + public object HelpTopic + { + get { return (object)this.GetValue(HelpTopicProperty); } + set { this.SetValue(HelpTopicProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HelpTopic. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HelpTopicProperty = + DependencyProperty.Register("HelpTopic", typeof(object), typeof(ScreenTip), new UIPropertyMetadata(null)); + + #endregion + + #region Image Property + + /// + /// Gets or sets image of the screen tip + /// + [System.ComponentModel.DisplayName("Image"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Image of the screen tip")] + public ImageSource Image + { + get { return (ImageSource)this.GetValue(ImageProperty); } + set { this.SetValue(ImageProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Image. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ImageProperty = + DependencyProperty.Register("Image", typeof(ImageSource), typeof(ScreenTip), new UIPropertyMetadata(null)); + + #endregion + + #region ShowHelp Property + /// + /// Shows or hides the Help Label + /// + [System.ComponentModel.DisplayName("HelpLabelVisibility"), + System.ComponentModel.Category("Screen Tip"), + System.ComponentModel.Description("Sets the visibility of the F1 Help Label")] + public Visibility HelpLabelVisibility + { + get { return (Visibility)this.GetValue(HelpLabelVisibilityProperty); } + set { this.SetValue(HelpLabelVisibilityProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store the boolean. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HelpLabelVisibilityProperty = + DependencyProperty.Register("HelpLabelVisibility", typeof(Visibility), typeof(ScreenTip), new UIPropertyMetadata(Visibility.Visible)); + #endregion + + #region Help Invocation + + /// + /// Occurs when user press F1 on ScreenTip with HelpTopic filled + /// + public static event EventHandler HelpPressed; + + #endregion + + #region IsRibbonAligned + + /// + /// Gets or set whether ScreenTip should positioned below Ribbon + /// + public bool IsRibbonAligned + { + get { return (bool)this.GetValue(IsRibbonAlignedProperty); } + set { this.SetValue(IsRibbonAlignedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for BelowRibbon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsRibbonAlignedProperty = + DependencyProperty.Register("BelowRibbon", typeof(bool), typeof(ScreenTip), + new UIPropertyMetadata(true)); + + + #endregion + + #region F1 Help Handling + + // Currently focused element + private IInputElement focusedElement; + + private void OnToolTipClosed(object sender, RoutedEventArgs e) + { + if (this.focusedElement == null) + { + return; + } + + this.focusedElement.PreviewKeyDown -= this.OnFocusedElementPreviewKeyDown; + this.focusedElement = null; + } + + private void OnToolTipOpened(object sender, RoutedEventArgs e) + { + if (this.HelpTopic == null) + { + return; + } + + this.focusedElement = Keyboard.FocusedElement; + if (this.focusedElement != null) + { + this.focusedElement.PreviewKeyDown += this.OnFocusedElementPreviewKeyDown; + } + } + + void OnFocusedElementPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key != Key.F1) + { + return; + } + + e.Handled = true; + + if (HelpPressed != null) + { + HelpPressed(null, new ScreenTipHelpEventArgs(this.HelpTopic)); + } + } + + #endregion + } + + /// + /// Event args for HelpPressed event handler + /// + public class ScreenTipHelpEventArgs : EventArgs + { + /// + /// Gets help topic associated with screen tip + /// + public object HelpTopic { get; private set; } + + /// + /// Constructor + /// + /// Help topic + public ScreenTipHelpEventArgs(object helpTopic) + { + this.HelpTopic = helpTopic; + } + } } \ No newline at end of file diff --git a/Fluent/Controls/SeparatorTabItem.cs b/Fluent.Ribbon/Controls/SeparatorTabItem.cs similarity index 97% rename from Fluent/Controls/SeparatorTabItem.cs rename to Fluent.Ribbon/Controls/SeparatorTabItem.cs index 2c3adbbe5..1e0251c92 100644 --- a/Fluent/Controls/SeparatorTabItem.cs +++ b/Fluent.Ribbon/Controls/SeparatorTabItem.cs @@ -1,61 +1,61 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; - -namespace Fluent -{ - /// - /// Represents separator to use in the TabControl - /// - public class SeparatorTabItem : TabItem - { - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static SeparatorTabItem() - { - Type type = typeof(SeparatorTabItem); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - IsEnabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); - IsTabStopProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); - IsSelectedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, OnIsSelectedChanged)); - StyleProperty.OverrideMetadata(typeof(SeparatorTabItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(SeparatorTabItem)); - } - - return basevalue; - } - - static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (!(bool)e.NewValue) return; - SeparatorTabItem separatorTabItem = (SeparatorTabItem)d; - TabControl tabControl = separatorTabItem.Parent as TabControl; - if (tabControl == null || tabControl.Items.Count <= 1) return; - tabControl.SelectedIndex = tabControl.SelectedIndex == tabControl.Items.Count - 1 - ? tabControl.SelectedIndex - 1 : - tabControl.SelectedIndex + 1; - } - - static object CoerceIsEnabledAndTabStop(DependencyObject d, object basevalue) - { - return false; - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; + +namespace Fluent +{ + /// + /// Represents separator to use in the TabControl + /// + public class SeparatorTabItem : TabItem + { + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static SeparatorTabItem() + { + Type type = typeof(SeparatorTabItem); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + IsEnabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); + IsTabStopProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, null, CoerceIsEnabledAndTabStop)); + IsSelectedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(false, OnIsSelectedChanged)); + StyleProperty.OverrideMetadata(typeof(SeparatorTabItem), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(SeparatorTabItem)); + } + + return basevalue; + } + + static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (!(bool)e.NewValue) return; + SeparatorTabItem separatorTabItem = (SeparatorTabItem)d; + TabControl tabControl = separatorTabItem.Parent as TabControl; + if (tabControl == null || tabControl.Items.Count <= 1) return; + tabControl.SelectedIndex = tabControl.SelectedIndex == tabControl.Items.Count - 1 + ? tabControl.SelectedIndex - 1 : + tabControl.SelectedIndex + 1; + } + + static object CoerceIsEnabledAndTabStop(DependencyObject d, object basevalue) + { + return false; + } + + #endregion + } +} diff --git a/Fluent/Controls/Spinner.cs b/Fluent.Ribbon/Controls/Spinner.cs similarity index 90% rename from Fluent/Controls/Spinner.cs rename to Fluent.Ribbon/Controls/Spinner.cs index 594c1dbae..3b5180b42 100644 --- a/Fluent/Controls/Spinner.cs +++ b/Fluent.Ribbon/Controls/Spinner.cs @@ -1,561 +1,545 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Text; - using System.Threading; - using System.Windows; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Input; - using System.Windows.Markup; - using System.Windows.Threading; - using Fluent.Internal; - - /// - /// Represents spinner control - /// - [ContentProperty("Value")] - [TemplatePart(Name = "PART_TextBox", Type = typeof(System.Windows.Controls.TextBox))] - [TemplatePart(Name = "PART_ButtonUp", Type = typeof(RepeatButton))] - [TemplatePart(Name = "PART_ButtonDown", Type = typeof(RepeatButton))] - public class Spinner : RibbonControl - { - #region Events - - /// - /// Occurs when value has been changed - /// - public event RoutedPropertyChangedEventHandler ValueChanged; - - #endregion - - #region Fields - - // Parts of the control (must be in control template) - private System.Windows.Controls.TextBox textBox; - private RepeatButton buttonUp; - private RepeatButton buttonDown; - - #endregion - - #region Properties - - #region Value - - /// - /// Gets or sets current value - /// - [SuppressMessage("Microsoft.Naming", "CA1721")] - public double Value - { - get { return (double)this.GetValue(ValueProperty); } - set { this.SetValue(ValueProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Value. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ValueProperty; - - private static object CoerceValue(DependencyObject d, object basevalue) - { - var spinner = (Spinner)d; - var value = (double)basevalue; - value = GetLimitedValue(spinner, value); - return value; - } - - private static double GetLimitedValue(Spinner spinner, double value) - { - value = Math.Max(spinner.Minimum, value); - value = Math.Min(spinner.Maximum, value); - return value; - } - - private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var spinner = (Spinner)d; - spinner.ValueToTextBoxText(); - - if (spinner.ValueChanged != null) - { - spinner.ValueChanged(spinner, new RoutedPropertyChangedEventArgs((double)e.OldValue, (double)e.NewValue)); - } - } - - private void ValueToTextBoxText() - { - if (this.IsTemplateValid()) - { - this.textBox.Text = this.Value.ToString(this.Format, CultureInfo.CurrentCulture); - this.Text = this.textBox.Text; - } - } - - #endregion - - #region Text - - /// - /// Gets current text from the spinner - /// - public string Text - { - get { return (string)this.GetValue(TextProperty); } - private set { this.SetValue(textPropertyKey, value); } - } - - private static readonly DependencyPropertyKey textPropertyKey = DependencyProperty.RegisterReadOnly("Text", typeof(string), typeof(Spinner), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for Text. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextProperty = textPropertyKey.DependencyProperty; - - #endregion - - #region Increment - - /// - /// Gets or sets a value added or subtracted from the value property - /// - public double Increment - { - get { return (double)this.GetValue(IncrementProperty); } - set { this.SetValue(IncrementProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Increment. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IncrementProperty = - DependencyProperty.Register("Increment", typeof(double), typeof(Spinner), new UIPropertyMetadata(1.0d)); - - #endregion - - #region Minimum - - /// - /// Gets or sets minimun value - /// - public double Minimum - { - get { return (double)this.GetValue(MinimumProperty); } - set { this.SetValue(MinimumProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Minimum. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MinimumProperty; - - static object CoerceMinimum(DependencyObject d, object basevalue) - { - var spinner = (Spinner)d; - var value = (double)basevalue; - - if (spinner.Maximum < value) - { - return spinner.Maximum; - } - - return value; - } - - static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var spinner = (Spinner)d; - var value = (double)CoerceValue(d, spinner.Value); - - if (DoubleUtil.AreClose(value, spinner.Value) == false) - { - spinner.Value = value; - } - } - - #endregion - - #region Maximum - - /// - /// Gets or sets maximum value - /// - public double Maximum - { - get { return (double)this.GetValue(MaximumProperty); } - set { this.SetValue(MaximumProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Maximum. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaximumProperty; - - static object CoerceMaximum(DependencyObject d, object basevalue) - { - var spinner = (Spinner)d; - var value = (double)basevalue; - - if (spinner.Minimum > value) - { - return spinner.Minimum; - } - - return value; - } - - static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var spinner = (Spinner)d; - var value = (double)CoerceValue(d, spinner.Value); - - if (DoubleUtil.AreClose(value, spinner.Value) == false) - { - spinner.Value = value; - } - } - - #endregion - - #region Format - - /// - /// Gets or sets string format of value - /// - public string Format - { - get { return (string)this.GetValue(FormatProperty); } - set { this.SetValue(FormatProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Format. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty FormatProperty = - DependencyProperty.Register("Format", typeof(string), typeof(Spinner), new UIPropertyMetadata("F1", OnFormatChanged)); - - static void OnFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var spinner = (Spinner)d; - spinner.ValueToTextBoxText(); - } - - #endregion - - #region Delay - - /// - /// Gets or sets the amount of time, in milliseconds, - /// the Spinner waits while it is pressed before it starts repeating. - /// The value must be non-negative. This is a dependency property. - /// - public int Delay - { - get { return (int)this.GetValue(DelayProperty); } - set { this.SetValue(DelayProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Delay. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DelayProperty = - DependencyProperty.Register("Delay", typeof(int), typeof(Spinner), - new UIPropertyMetadata(400)); - - #endregion - - #region Interval - - /// - /// Gets or sets the amount of time, in milliseconds, - /// between repeats once repeating starts. The value must be non-negative. - /// This is a dependency property. - /// - public int Interval - { - get { return (int)this.GetValue(IntervalProperty); } - set { this.SetValue(IntervalProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Interval. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IntervalProperty = - DependencyProperty.Register("Interval", typeof(int), typeof(Spinner), new UIPropertyMetadata(80)); - - #endregion - - #region InputWidth - - /// - /// Gets or sets width of the value input part of spinner - /// - public double InputWidth - { - get { return (double)this.GetValue(InputWidthProperty); } - set { this.SetValue(InputWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty InputWidthProperty = - DependencyProperty.Register("InputWidth", typeof(double), typeof(Spinner), new UIPropertyMetadata(double.NaN)); - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static Spinner() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(Spinner), new FrameworkPropertyMetadata(typeof(Spinner))); - - MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(Spinner), new UIPropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum)); - MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(Spinner), new UIPropertyMetadata(0.0d, OnMinimumChanged, CoerceMinimum)); - ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(Spinner), new FrameworkPropertyMetadata(0.0d, OnValueChanged, CoerceValue) { BindsTwoWayByDefault = true }); - - KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(Spinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - if (this.IsTemplateValid()) - { - this.buttonUp.Click -= this.OnButtonUpClick; - this.buttonDown.Click -= this.OnButtonDownClick; - BindingOperations.ClearAllBindings(this.buttonDown); - BindingOperations.ClearAllBindings(this.buttonUp); - } - - // Get template childs - this.textBox = this.GetTemplateChild("PART_TextBox") as System.Windows.Controls.TextBox; - this.buttonUp = this.GetTemplateChild("PART_ButtonUp") as RepeatButton; - this.buttonDown = this.GetTemplateChild("PART_ButtonDown") as RepeatButton; - - // Check template - if (this.IsTemplateValid() == false) - { - Debug.WriteLine("Template for Spinner control is invalid"); - return; - } - - // Bindings - Bind(this, this.buttonUp, "Delay", RepeatButton.DelayProperty, BindingMode.OneWay); - Bind(this, this.buttonDown, "Delay", RepeatButton.DelayProperty, BindingMode.OneWay); - Bind(this, this.buttonUp, "Interval", RepeatButton.IntervalProperty, BindingMode.OneWay); - Bind(this, this.buttonDown, "Interval", RepeatButton.IntervalProperty, BindingMode.OneWay); - - - // Events subscribing - this.buttonUp.Click += this.OnButtonUpClick; - this.buttonDown.Click += this.OnButtonDownClick; - this.textBox.LostKeyboardFocus += this.OnTextBoxLostKeyboardFocus; - this.textBox.PreviewKeyDown += this.OnTextBoxPreviewKeyDown; - - this.ValueToTextBoxText(); - } - - bool IsTemplateValid() - { - return this.textBox != null - && this.buttonUp != null - && this.buttonDown != null; - } - - #endregion - - #region Event Handling - - /// - /// Handles key tip pressed - /// - public override void OnKeyTipPressed() - { - if (this.IsTemplateValid() == false) - { - return; - } - - // Use dispatcher to avoid focus moving to backup'ed element - // (focused element before keytips processing) - this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, - (ThreadStart)(() => - { - this.textBox.SelectAll(); - this.textBox.Focus(); - })); - base.OnKeyTipPressed(); - } - - /// - /// Invoked when an unhandled System.Windows.Input.Keyboard.KeyUp�attached event reaches - /// an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.KeyEventArgs that contains the event data. - protected override void OnKeyUp(KeyEventArgs e) - { - // Avoid Click invocation (from RibbonControl) - if (e.Key == Key.Enter - || e.Key == Key.Space) - { - return; - } - - base.OnKeyUp(e); - } - - private void OnButtonUpClick(object sender, RoutedEventArgs e) - { - this.Value = GetLimitedValue(this, this.Value + this.Increment); - } - - private void OnButtonDownClick(object sender, RoutedEventArgs e) - { - this.Value = GetLimitedValue(this, this.Value - this.Increment); - } - - private void OnTextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - this.TextBoxTextToValue(); - } - - private void OnTextBoxPreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Enter) - { - this.TextBoxTextToValue(); - } - - if (e.Key == Key.Escape) - { - this.ValueToTextBoxText(); - } - - if (e.Key == Key.Enter - || e.Key == Key.Escape) - { - // Move Focus - this.textBox.Focusable = false; - this.Focus(); - this.textBox.Focusable = true; - e.Handled = true; - } - - if (e.Key == Key.Up) - { - this.buttonUp.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); - } - - if (e.Key == Key.Down) - { - this.buttonDown.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); - } - } - - private void TextBoxTextToValue() - { - var text = this.textBox.Text; - - // Remove all except digits, signs and commas - var stringBuilder = new StringBuilder(); - - foreach (var symbol in text) - { - if (char.IsDigit(symbol) - || symbol == ',' - || symbol == '.' - || (symbol == '-' && stringBuilder.Length == 0)) - { - stringBuilder.Append(symbol); - } - } - - text = stringBuilder.ToString(); - - double value; - - if (double.TryParse(text, NumberStyles.Any, CultureInfo.CurrentCulture, out value)) - { - this.Value = GetLimitedValue(this, value); - } - - this.ValueToTextBoxText(); - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - var spinner = new Spinner(); - this.BindQuickAccessItem(spinner); - return spinner; - } - - /// - /// This method must be overriden to bind properties to use in quick access creating - /// - /// Toolbar item - protected void BindQuickAccessItem(FrameworkElement element) - { - var spinner = (Spinner)element; - - BindQuickAccessItem(this, element); - - spinner.Width = this.Width; - spinner.InputWidth = this.InputWidth; - - Bind(this, spinner, "Value", ValueProperty, BindingMode.TwoWay); - Bind(this, spinner, "Increment", IncrementProperty, BindingMode.OneWay); - Bind(this, spinner, "Minimum", MinimumProperty, BindingMode.OneWay); - Bind(this, spinner, "Maximum", MaximumProperty, BindingMode.OneWay); - Bind(this, spinner, "Format", FormatProperty, BindingMode.OneWay); - Bind(this, spinner, "Delay", DelayProperty, BindingMode.OneWay); - Bind(this, spinner, "Interval", IntervalProperty, BindingMode.OneWay); - - BindQuickAccessItem(this, element); - } - - #endregion - } +namespace Fluent +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Text; + using System.Threading; + using System.Windows; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Markup; + using System.Windows.Threading; + using Fluent.Converters; + using Fluent.Internal; + + /// + /// Represents spinner control + /// + [ContentProperty("Value")] + [TemplatePart(Name = "PART_TextBox", Type = typeof(System.Windows.Controls.TextBox))] + [TemplatePart(Name = "PART_ButtonUp", Type = typeof(RepeatButton))] + [TemplatePart(Name = "PART_ButtonDown", Type = typeof(RepeatButton))] + public class Spinner : RibbonControl + { + /// + /// Occurs when value has been changed + /// + public event RoutedPropertyChangedEventHandler ValueChanged; + + // Parts of the control (must be in control template) + private System.Windows.Controls.TextBox textBox; + private RepeatButton buttonUp; + private RepeatButton buttonDown; + + #region Properties + + #region Value + + /// + /// Gets or sets current value + /// + [SuppressMessage("Microsoft.Naming", "CA1721")] + public double Value + { + get { return (double)this.GetValue(ValueProperty); } + set { this.SetValue(ValueProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Value. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ValueProperty; + + private static object CoerceValue(DependencyObject d, object basevalue) + { + var spinner = (Spinner)d; + var value = (double)basevalue; + value = GetLimitedValue(spinner, value); + return value; + } + + private static double GetLimitedValue(Spinner spinner, double value) + { + value = Math.Max(spinner.Minimum, value); + value = Math.Min(spinner.Maximum, value); + return value; + } + + private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var spinner = (Spinner)d; + spinner.ValueToTextBoxText(); + + if (spinner.ValueChanged != null) + { + spinner.ValueChanged(spinner, new RoutedPropertyChangedEventArgs((double)e.OldValue, (double)e.NewValue)); + } + } + + private void ValueToTextBoxText() + { + if (this.IsTemplateValid()) + { + var newText = (string)this.TextToValueConverter.ConvertBack(this.Value, typeof(string), this.Format, CultureInfo.CurrentCulture); + this.textBox.Text = newText; + this.Text = newText; + } + } + + #endregion + + #region Text + + /// + /// Gets current text from the spinner + /// + public string Text + { + get { return (string)this.GetValue(TextProperty); } + private set { this.SetValue(textPropertyKey, value); } + } + + private static readonly DependencyPropertyKey textPropertyKey = DependencyProperty.RegisterReadOnly("Text", typeof(string), typeof(Spinner), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for Text. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextProperty = textPropertyKey.DependencyProperty; + + #endregion + + #region Increment + + /// + /// Gets or sets a value added or subtracted from the value property + /// + public double Increment + { + get { return (double)this.GetValue(IncrementProperty); } + set { this.SetValue(IncrementProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Increment. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IncrementProperty = + DependencyProperty.Register("Increment", typeof(double), typeof(Spinner), new UIPropertyMetadata(1.0d)); + + #endregion + + #region Minimum + + /// + /// Gets or sets minimun value + /// + public double Minimum + { + get { return (double)this.GetValue(MinimumProperty); } + set { this.SetValue(MinimumProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Minimum. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MinimumProperty; + + static object CoerceMinimum(DependencyObject d, object basevalue) + { + var spinner = (Spinner)d; + var value = (double)basevalue; + + if (spinner.Maximum < value) + { + return spinner.Maximum; + } + + return value; + } + + static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var spinner = (Spinner)d; + var value = (double)CoerceValue(d, spinner.Value); + + if (DoubleUtil.AreClose(value, spinner.Value) == false) + { + spinner.Value = value; + } + } + + #endregion + + #region Maximum + + /// + /// Gets or sets maximum value + /// + public double Maximum + { + get { return (double)this.GetValue(MaximumProperty); } + set { this.SetValue(MaximumProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Maximum. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaximumProperty; + + static object CoerceMaximum(DependencyObject d, object basevalue) + { + var spinner = (Spinner)d; + var value = (double)basevalue; + + if (spinner.Minimum > value) + { + return spinner.Minimum; + } + + return value; + } + + static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var spinner = (Spinner)d; + var value = (double)CoerceValue(d, spinner.Value); + + if (DoubleUtil.AreClose(value, spinner.Value) == false) + { + spinner.Value = value; + } + } + + #endregion + + #region Format + + /// + /// Gets or sets string format of value + /// + public string Format + { + get { return (string)this.GetValue(FormatProperty); } + set { this.SetValue(FormatProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Format. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty FormatProperty = + DependencyProperty.Register("Format", typeof(string), typeof(Spinner), new UIPropertyMetadata("F1", OnFormatChanged)); + + static void OnFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var spinner = (Spinner)d; + spinner.ValueToTextBoxText(); + } + + #endregion + + #region Delay + + /// + /// Gets or sets the amount of time, in milliseconds, + /// the Spinner waits while it is pressed before it starts repeating. + /// The value must be non-negative. This is a dependency property. + /// + public int Delay + { + get { return (int)this.GetValue(DelayProperty); } + set { this.SetValue(DelayProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Delay. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DelayProperty = + DependencyProperty.Register("Delay", typeof(int), typeof(Spinner), + new UIPropertyMetadata(400)); + + #endregion + + #region Interval + + /// + /// Gets or sets the amount of time, in milliseconds, + /// between repeats once repeating starts. The value must be non-negative. + /// This is a dependency property. + /// + public int Interval + { + get { return (int)this.GetValue(IntervalProperty); } + set { this.SetValue(IntervalProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Interval. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IntervalProperty = + DependencyProperty.Register("Interval", typeof(int), typeof(Spinner), new UIPropertyMetadata(80)); + + #endregion + + #region InputWidth + + /// + /// Gets or sets width of the value input part of spinner + /// + public double InputWidth + { + get { return (double)this.GetValue(InputWidthProperty); } + set { this.SetValue(InputWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty InputWidthProperty = + DependencyProperty.Register("InputWidth", typeof(double), typeof(Spinner), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region TextToValueConverter + + /// + /// Gets or sets a converter which is used to convert from text to double and from double to text. + /// + public IValueConverter TextToValueConverter + { + get { return (IValueConverter)this.GetValue(TextToValueConverterProperty); } + set { this.SetValue(TextToValueConverterProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for TextToValueConverter. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextToValueConverterProperty = + DependencyProperty.Register(nameof(TextToValueConverter), typeof(IValueConverter), typeof(Spinner), new PropertyMetadata(new SpinnerTextToValueConverter())); + + #endregion TextToValueConverter + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static Spinner() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(Spinner), new FrameworkPropertyMetadata(typeof(Spinner))); + + MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(Spinner), new UIPropertyMetadata(double.MaxValue, OnMaximumChanged, CoerceMaximum)); + MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(Spinner), new UIPropertyMetadata(0.0d, OnMinimumChanged, CoerceMinimum)); + ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(Spinner), new FrameworkPropertyMetadata(0.0d, OnValueChanged, CoerceValue) { BindsTwoWayByDefault = true }); + + KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(Spinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once)); + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + if (this.IsTemplateValid()) + { + this.buttonUp.Click -= this.OnButtonUpClick; + this.buttonDown.Click -= this.OnButtonDownClick; + BindingOperations.ClearAllBindings(this.buttonDown); + BindingOperations.ClearAllBindings(this.buttonUp); + } + + // Get template childs + this.textBox = this.GetTemplateChild("PART_TextBox") as System.Windows.Controls.TextBox; + this.buttonUp = this.GetTemplateChild("PART_ButtonUp") as RepeatButton; + this.buttonDown = this.GetTemplateChild("PART_ButtonDown") as RepeatButton; + + // Check template + if (this.IsTemplateValid() == false) + { + Debug.WriteLine("Template for Spinner control is invalid"); + return; + } + + // Bindings + Bind(this, this.buttonUp, "Delay", RepeatButton.DelayProperty, BindingMode.OneWay); + Bind(this, this.buttonDown, "Delay", RepeatButton.DelayProperty, BindingMode.OneWay); + Bind(this, this.buttonUp, "Interval", RepeatButton.IntervalProperty, BindingMode.OneWay); + Bind(this, this.buttonDown, "Interval", RepeatButton.IntervalProperty, BindingMode.OneWay); + + + // Events subscribing + this.buttonUp.Click += this.OnButtonUpClick; + this.buttonDown.Click += this.OnButtonDownClick; + this.textBox.LostKeyboardFocus += this.OnTextBoxLostKeyboardFocus; + this.textBox.PreviewKeyDown += this.OnTextBoxPreviewKeyDown; + + this.ValueToTextBoxText(); + } + + bool IsTemplateValid() + { + return this.textBox != null + && this.buttonUp != null + && this.buttonDown != null; + } + + #endregion + + #region Event Handling + + /// + /// Handles key tip pressed + /// + public override void OnKeyTipPressed() + { + if (this.IsTemplateValid() == false) + { + return; + } + + // Use dispatcher to avoid focus moving to backup'ed element + // (focused element before keytips processing) + this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, + (ThreadStart)(() => + { + this.textBox.SelectAll(); + this.textBox.Focus(); + })); + base.OnKeyTipPressed(); + } + + /// + /// Invoked when an unhandled System.Windows.Input.Keyboard.KeyUp�attached event reaches + /// an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.KeyEventArgs that contains the event data. + protected override void OnKeyUp(KeyEventArgs e) + { + // Avoid Click invocation (from RibbonControl) + if (e.Key == Key.Enter + || e.Key == Key.Space) + { + return; + } + + base.OnKeyUp(e); + } + + private void OnButtonUpClick(object sender, RoutedEventArgs e) + { + this.Value = GetLimitedValue(this, this.Value + this.Increment); + } + + private void OnButtonDownClick(object sender, RoutedEventArgs e) + { + this.Value = GetLimitedValue(this, this.Value - this.Increment); + } + + private void OnTextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + this.TextBoxTextToValue(); + } + + private void OnTextBoxPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + this.TextBoxTextToValue(); + } + + if (e.Key == Key.Escape) + { + this.ValueToTextBoxText(); + } + + if (e.Key == Key.Enter + || e.Key == Key.Escape) + { + // Move Focus + this.textBox.Focusable = false; + this.Focus(); + this.textBox.Focusable = true; + e.Handled = true; + } + + if (e.Key == Key.Up) + { + this.buttonUp.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); + } + + if (e.Key == Key.Down) + { + this.buttonDown.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); + } + } + + private void TextBoxTextToValue() + { + var converterParam = new Tuple(this.Format, this.Value); + var newValue = (double)this.TextToValueConverter.Convert(this.textBox.Text, typeof(double), converterParam, CultureInfo.CurrentCulture); + + this.Value = GetLimitedValue(this, newValue); + + this.ValueToTextBoxText(); + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + var spinner = new Spinner(); + this.BindQuickAccessItem(spinner); + return spinner; + } + + /// + /// This method must be overriden to bind properties to use in quick access creating + /// + /// Toolbar item + protected void BindQuickAccessItem(FrameworkElement element) + { + var spinner = (Spinner)element; + + BindQuickAccessItem(this, element); + + spinner.Width = this.Width; + spinner.InputWidth = this.InputWidth; + + Bind(this, spinner, "Value", ValueProperty, BindingMode.TwoWay); + Bind(this, spinner, "Increment", IncrementProperty, BindingMode.OneWay); + Bind(this, spinner, "Minimum", MinimumProperty, BindingMode.OneWay); + Bind(this, spinner, "Maximum", MaximumProperty, BindingMode.OneWay); + Bind(this, spinner, "Format", FormatProperty, BindingMode.OneWay); + Bind(this, spinner, "Delay", DelayProperty, BindingMode.OneWay); + Bind(this, spinner, "Interval", IntervalProperty, BindingMode.OneWay); + + BindQuickAccessItem(this, element); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/SplitButton.cs b/Fluent.Ribbon/Controls/SplitButton.cs similarity index 95% rename from Fluent/Controls/SplitButton.cs rename to Fluent.Ribbon/Controls/SplitButton.cs index a08b7108a..7ea29845e 100644 --- a/Fluent/Controls/SplitButton.cs +++ b/Fluent.Ribbon/Controls/SplitButton.cs @@ -1,530 +1,521 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Collections; -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Input; - -namespace Fluent -{ - /// - /// Represents button control that allows - /// you to add menu and handle clicks - /// - [TemplatePart(Name = "PART_Button", Type = typeof(ButtonBase))] - public class SplitButton : DropDownButton, IToggleButton, ICommandSource - { - #region Fields - - // Inner button - ToggleButton button; - - #endregion - - #region Properties - - /// - /// Gets an enumerator for logical child elements of this element. - /// - protected override IEnumerator LogicalChildren - { - get - { - var baseEnumerator = base.LogicalChildren; - while (baseEnumerator.MoveNext()) - { - yield return baseEnumerator.Current; - } - - if (this.button != null) - { - yield return this.button; - } - } - } - - #region Command - - /// - /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. - /// - [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] - public ICommand Command - { - get - { - return (ICommand)this.GetValue(CommandProperty); - } - set - { - this.SetValue(CommandProperty, value); - } - } - - /// - /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. - /// - [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] - public object CommandParameter - { - get - { - return this.GetValue(CommandParameterProperty); - } - set - { - this.SetValue(CommandParameterProperty, value); - } - } - - /// - /// Gets or sets the element on which to raise the specified command. This is a dependency property. - /// - [Bindable(true), Category("Action")] - public IInputElement CommandTarget - { - get - { - return (IInputElement)this.GetValue(CommandTargetProperty); - } - set - { - this.SetValue(CommandTargetProperty, value); - } - } - - /// - /// Identifies the CommandParameter dependency property. - /// - public static readonly DependencyProperty CommandParameterProperty = ButtonBase.CommandParameterProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); - /// - /// Identifies the routed Command dependency property. - /// - public static readonly DependencyProperty CommandProperty = ButtonBase.CommandProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); - - /// - /// Identifies the CommandTarget dependency property. - /// - public static readonly DependencyProperty CommandTargetProperty = ButtonBase.CommandTargetProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); - - #endregion - - #region GroupName - - /// - /// Gets or sets the name of the group that the toggle button belongs to. - /// Use the GroupName property to specify a grouping of toggle buttons to - /// create a mutually exclusive set of controls. You can use the GroupName - /// property when only one selection is possible from a list of available - /// options. When this property is set, only one ToggleButton in the specified - /// group can be selected at a time. - /// - public string GroupName - { - get { return (string)this.GetValue(GroupNameProperty); } - set { this.SetValue(GroupNameProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupName. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupNameProperty = - DependencyProperty.Register("GroupName", typeof(string), typeof(SplitButton), - new UIPropertyMetadata(null, ToggleButtonHelper.OnGroupNameChanged)); - - #endregion - - #region IsChecked - - /// - /// Gets or sets a value indicating whether SplitButton is checked - /// - public bool? IsChecked - { - get { return (bool)this.GetValue(IsCheckedProperty); } - set { this.SetValue(IsCheckedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCheckedProperty = - DependencyProperty.Register("IsChecked", typeof(bool?), typeof(SplitButton), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsCheckedChanged, CoerceIsChecked)); - - private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - SplitButton button = d as SplitButton; - if (button.IsCheckable) - { - if ((bool)e.NewValue) button.RaiseEvent(new RoutedEventArgs(CheckedEvent, button)); - else button.RaiseEvent(new RoutedEventArgs(UncheckedEvent, button)); - - ToggleButtonHelper.OnIsCheckedChanged(d, e); - } - } - - private static object CoerceIsChecked(DependencyObject d, object basevalue) - { - SplitButton button = d as SplitButton; - - if (!button.IsCheckable) return false; - - return ToggleButtonHelper.CoerceIsChecked(d, basevalue); - } - - #endregion - - #region IsCheckable - - /// - /// Gets or sets a value indicating whether SplitButton can be checked - /// - public bool IsCheckable - { - get { return (bool)this.GetValue(IsCheckableProperty); } - set { this.SetValue(IsCheckableProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCheckableProperty = - DependencyProperty.Register("IsCheckable", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(false)); - - #endregion - - #region DropDownToolTip - - /// - /// Gets or sets tooltip of dropdown part of split button - /// - public object DropDownToolTip - { - get { return this.GetValue(DropDownToolTipProperty); } - set { this.SetValue(DropDownToolTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for DropDownToolTip. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty DropDownToolTipProperty = - DependencyProperty.Register("DropDownToolTip", typeof(object), typeof(SplitButton), new UIPropertyMetadata(null)); - - #endregion - - #region IsButtonEnabled - - /// - /// Gets or sets a value indicating whether dropdown part of split button is enabled - /// - public bool IsButtonEnabled - { - get { return (bool)this.GetValue(IsButtonEnabledProperty); } - set { this.SetValue(IsButtonEnabledProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsDropDownEnabled. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsButtonEnabledProperty = - DependencyProperty.Register("IsButtonEnabled", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true)); - - #endregion - - #region IsDefinitive - - /// - /// Gets or sets whether ribbon control click must close backstage - /// - public bool IsDefinitive - { - get { return (bool)this.GetValue(IsDefinitiveProperty); } - set { this.SetValue(IsDefinitiveProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDefinitiveProperty = - DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true)); - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when user clicks - /// - public static readonly RoutedEvent ClickEvent = ButtonBase.ClickEvent.AddOwner(typeof(SplitButton)); - - /// - /// Occurs when user clicks - /// - public event RoutedEventHandler Click - { - add - { - this.AddHandler(ClickEvent, value); - } - - remove - { - this.RemoveHandler(ClickEvent, value); - } - } - - /// - /// Occurs when button is checked - /// - public static readonly RoutedEvent CheckedEvent = System.Windows.Controls.Primitives.ToggleButton.CheckedEvent.AddOwner(typeof(SplitButton)); - - /// - /// Occurs when button is checked - /// - public event RoutedEventHandler Checked - { - add - { - this.AddHandler(CheckedEvent, value); - } - - remove - { - this.RemoveHandler(CheckedEvent, value); - } - } - - /// - /// Occurs when button is unchecked - /// - public static readonly RoutedEvent UncheckedEvent = System.Windows.Controls.Primitives.ToggleButton.UncheckedEvent.AddOwner(typeof(SplitButton)); - - /// - /// Occurs when button is unchecked - /// - public event RoutedEventHandler Unchecked - { - add - { - this.AddHandler(UncheckedEvent, value); - } - - remove - { - this.RemoveHandler(UncheckedEvent, value); - } - } - - #endregion - - #region Constructors - - [SuppressMessage("Microsoft.Performance", "CA1810")] - static SplitButton() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(typeof(SplitButton))); - FocusVisualStyleProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(null)); - StyleProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(SplitButton)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public SplitButton() - { - ContextMenuService.Coerce(this); - this.Click += this.OnClick; - // AddHandler(ClickEvent, OnClick); - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - this.SubscribeEvents(); - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - this.UnSubscribeEvents(); - } - - private void SubscribeEvents() - { - // Always unsubscribe events to ensure we don't subscribe twice - this.UnSubscribeEvents(); - - if (this.button != null) - { - this.button.Click += this.OnButtonClick; - } - } - - private void UnSubscribeEvents() - { - if (this.button != null) - { - this.button.Click -= this.OnButtonClick; - } - } - - private void OnClick(object sender, RoutedEventArgs e) - { - if (e.OriginalSource != this && e.OriginalSource != this._quickAccessButton) - { - e.Handled = true; - } - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked - /// whenever application code or internal processes call ApplyTemplate - /// - public override void OnApplyTemplate() - { - this.UnSubscribeEvents(); - - this.button = this.GetTemplateChild("PART_Button") as ToggleButton; - - base.OnApplyTemplate(); - - this.SubscribeEvents(); - } - /// - /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDown routed event - /// reaches an element in its route that is derived from this class. Implement this method to add - /// class handling for this event. - /// - /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. - /// The event data reports that the left mouse button was pressed. - protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) - { - if (!PopupService.IsMousePhysicallyOver(this.button)) - { - base.OnPreviewMouseLeftButtonDown(e); - } - else - { - this.IsDropDownOpen = false; - } - } - - #region Overrides of DropDownButton - - /// - /// Provides class handling for the routed event that occurs when the user presses a key. - /// - /// The event data for the event. - protected override void OnKeyDown(KeyEventArgs e) - { - base.OnKeyDown(e); - - if (e.Key == Key.Enter) - { - this.button.InvokeClick(); - } - } - - #endregion - - private void OnButtonClick(object sender, RoutedEventArgs e) - { - e.Handled = true; - this.RaiseEvent(new RoutedEventArgs(ClickEvent, this)); - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be synchronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - SplitButton button = new SplitButton(); - button.Click += ((sender, e) => this.RaiseEvent(e)); - RibbonProperties.SetSize(button, RibbonControlSize.Small); - button.CanAddButtonToQuickAccessToolBar = false; - this.BindQuickAccessItem(button); - this.BindQuickAccessItemDropDownEvents(button); - button.DropDownOpened += this.OnQuickAccessOpened; - this._quickAccessButton = button; - return button; - } - - /// - /// This method must be overridden to bind properties to use in quick access creating - /// - /// Toolbar item - protected override void BindQuickAccessItem(FrameworkElement element) - { - RibbonControl.Bind(this, element, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); - RibbonControl.Bind(this, element, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); - RibbonControl.Bind(this, element, "DropDownToolTip", DropDownToolTipProperty, BindingMode.TwoWay); - RibbonControl.Bind(this, element, "IsCheckable", IsCheckableProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "IsButtonEnabled", IsButtonEnabledProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "ContextMenu", ContextMenuProperty, BindingMode.Default); - RibbonControl.BindQuickAccessItem(this, element); - RibbonControl.Bind(this, element, "ResizeMode", ResizeModeProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); - RibbonControl.Bind(this, element, "HasTriangle", HasTriangleProperty, BindingMode.Default); - } - - /// - /// Gets or sets whether button can be added to quick access toolbar - /// - public bool CanAddButtonToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddButtonToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddButtonToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddButtonToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddButtonToQuickAccessToolBarProperty = DependencyProperty.Register("CanAddButtonToQuickAccessToolBar", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - private SplitButton _quickAccessButton; - - #endregion - } -} +using System.Collections; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; + +namespace Fluent +{ + /// + /// Represents button control that allows + /// you to add menu and handle clicks + /// + [TemplatePart(Name = "PART_Button", Type = typeof(ButtonBase))] + public class SplitButton : DropDownButton, IToggleButton, ICommandSource + { + #region Fields + + // Inner button + ToggleButton button; + + #endregion + + #region Properties + + /// + /// Gets an enumerator for logical child elements of this element. + /// + protected override IEnumerator LogicalChildren + { + get + { + var baseEnumerator = base.LogicalChildren; + while (baseEnumerator.MoveNext()) + { + yield return baseEnumerator.Current; + } + + if (this.button != null) + { + yield return this.button; + } + } + } + + #region Command + + /// + /// Gets or sets the command to invoke when this button is pressed. This is a dependency property. + /// + [Category("Action"), Localizability(LocalizationCategory.NeverLocalize), Bindable(true)] + public ICommand Command + { + get + { + return (ICommand)this.GetValue(CommandProperty); + } + set + { + this.SetValue(CommandProperty, value); + } + } + + /// + /// Gets or sets the parameter to pass to the System.Windows.Controls.Primitives.ButtonBase.Command property. This is a dependency property. + /// + [Bindable(true), Localizability(LocalizationCategory.NeverLocalize), Category("Action")] + public object CommandParameter + { + get + { + return this.GetValue(CommandParameterProperty); + } + set + { + this.SetValue(CommandParameterProperty, value); + } + } + + /// + /// Gets or sets the element on which to raise the specified command. This is a dependency property. + /// + [Bindable(true), Category("Action")] + public IInputElement CommandTarget + { + get + { + return (IInputElement)this.GetValue(CommandTargetProperty); + } + set + { + this.SetValue(CommandTargetProperty, value); + } + } + + /// + /// Identifies the CommandParameter dependency property. + /// + public static readonly DependencyProperty CommandParameterProperty = ButtonBase.CommandParameterProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); + /// + /// Identifies the routed Command dependency property. + /// + public static readonly DependencyProperty CommandProperty = ButtonBase.CommandProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); + + /// + /// Identifies the CommandTarget dependency property. + /// + public static readonly DependencyProperty CommandTargetProperty = ButtonBase.CommandTargetProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(null)); + + #endregion + + #region GroupName + + /// + /// Gets or sets the name of the group that the toggle button belongs to. + /// Use the GroupName property to specify a grouping of toggle buttons to + /// create a mutually exclusive set of controls. You can use the GroupName + /// property when only one selection is possible from a list of available + /// options. When this property is set, only one ToggleButton in the specified + /// group can be selected at a time. + /// + public string GroupName + { + get { return (string)this.GetValue(GroupNameProperty); } + set { this.SetValue(GroupNameProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupName. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupNameProperty = + DependencyProperty.Register("GroupName", typeof(string), typeof(SplitButton), + new UIPropertyMetadata(null, ToggleButtonHelper.OnGroupNameChanged)); + + #endregion + + #region IsChecked + + /// + /// Gets or sets a value indicating whether SplitButton is checked + /// + public bool? IsChecked + { + get { return (bool)this.GetValue(IsCheckedProperty); } + set { this.SetValue(IsCheckedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCheckedProperty = + DependencyProperty.Register("IsChecked", typeof(bool?), typeof(SplitButton), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsCheckedChanged, CoerceIsChecked)); + + private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + SplitButton button = d as SplitButton; + if (button.IsCheckable) + { + if ((bool)e.NewValue) button.RaiseEvent(new RoutedEventArgs(CheckedEvent, button)); + else button.RaiseEvent(new RoutedEventArgs(UncheckedEvent, button)); + + ToggleButtonHelper.OnIsCheckedChanged(d, e); + } + } + + private static object CoerceIsChecked(DependencyObject d, object basevalue) + { + SplitButton button = d as SplitButton; + + if (!button.IsCheckable) return false; + + return ToggleButtonHelper.CoerceIsChecked(d, basevalue); + } + + #endregion + + #region IsCheckable + + /// + /// Gets or sets a value indicating whether SplitButton can be checked + /// + public bool IsCheckable + { + get { return (bool)this.GetValue(IsCheckableProperty); } + set { this.SetValue(IsCheckableProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCheckableProperty = + DependencyProperty.Register("IsCheckable", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(false)); + + #endregion + + #region DropDownToolTip + + /// + /// Gets or sets tooltip of dropdown part of split button + /// + public object DropDownToolTip + { + get { return this.GetValue(DropDownToolTipProperty); } + set { this.SetValue(DropDownToolTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for DropDownToolTip. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty DropDownToolTipProperty = + DependencyProperty.Register("DropDownToolTip", typeof(object), typeof(SplitButton), new UIPropertyMetadata(null)); + + #endregion + + #region IsButtonEnabled + + /// + /// Gets or sets a value indicating whether dropdown part of split button is enabled + /// + public bool IsButtonEnabled + { + get { return (bool)this.GetValue(IsButtonEnabledProperty); } + set { this.SetValue(IsButtonEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsDropDownEnabled. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsButtonEnabledProperty = + DependencyProperty.Register("IsButtonEnabled", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true)); + + #endregion + + #region IsDefinitive + + /// + /// Gets or sets whether ribbon control click must close backstage + /// + public bool IsDefinitive + { + get { return (bool)this.GetValue(IsDefinitiveProperty); } + set { this.SetValue(IsDefinitiveProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDefinitiveProperty = + DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true)); + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when user clicks + /// + public static readonly RoutedEvent ClickEvent = ButtonBase.ClickEvent.AddOwner(typeof(SplitButton)); + + /// + /// Occurs when user clicks + /// + public event RoutedEventHandler Click + { + add + { + this.AddHandler(ClickEvent, value); + } + + remove + { + this.RemoveHandler(ClickEvent, value); + } + } + + /// + /// Occurs when button is checked + /// + public static readonly RoutedEvent CheckedEvent = System.Windows.Controls.Primitives.ToggleButton.CheckedEvent.AddOwner(typeof(SplitButton)); + + /// + /// Occurs when button is checked + /// + public event RoutedEventHandler Checked + { + add + { + this.AddHandler(CheckedEvent, value); + } + + remove + { + this.RemoveHandler(CheckedEvent, value); + } + } + + /// + /// Occurs when button is unchecked + /// + public static readonly RoutedEvent UncheckedEvent = System.Windows.Controls.Primitives.ToggleButton.UncheckedEvent.AddOwner(typeof(SplitButton)); + + /// + /// Occurs when button is unchecked + /// + public event RoutedEventHandler Unchecked + { + add + { + this.AddHandler(UncheckedEvent, value); + } + + remove + { + this.RemoveHandler(UncheckedEvent, value); + } + } + + #endregion + + #region Constructors + + [SuppressMessage("Microsoft.Performance", "CA1810")] + static SplitButton() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(typeof(SplitButton))); + FocusVisualStyleProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(null)); + StyleProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(SplitButton)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public SplitButton() + { + ContextMenuService.Coerce(this); + this.Click += this.OnClick; + // AddHandler(ClickEvent, OnClick); + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + this.SubscribeEvents(); + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + this.UnSubscribeEvents(); + } + + private void SubscribeEvents() + { + // Always unsubscribe events to ensure we don't subscribe twice + this.UnSubscribeEvents(); + + if (this.button != null) + { + this.button.Click += this.OnButtonClick; + } + } + + private void UnSubscribeEvents() + { + if (this.button != null) + { + this.button.Click -= this.OnButtonClick; + } + } + + private void OnClick(object sender, RoutedEventArgs e) + { + if (e.OriginalSource != this && e.OriginalSource != this._quickAccessButton) + { + e.Handled = true; + } + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked + /// whenever application code or internal processes call ApplyTemplate + /// + public override void OnApplyTemplate() + { + this.UnSubscribeEvents(); + + this.button = this.GetTemplateChild("PART_Button") as ToggleButton; + + base.OnApplyTemplate(); + + this.SubscribeEvents(); + } + /// + /// Invoked when an unhandled System.Windows.UIElement.PreviewMouseLeftButtonDown routed event + /// reaches an element in its route that is derived from this class. Implement this method to add + /// class handling for this event. + /// + /// The System.Windows.Input.MouseButtonEventArgs that contains the event data. + /// The event data reports that the left mouse button was pressed. + protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) + { + if (!PopupService.IsMousePhysicallyOver(this.button)) + { + base.OnPreviewMouseLeftButtonDown(e); + } + else + { + this.IsDropDownOpen = false; + } + } + + #region Overrides of DropDownButton + + /// + /// Provides class handling for the routed event that occurs when the user presses a key. + /// + /// The event data for the event. + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.Key == Key.Enter) + { + this.button.InvokeClick(); + } + } + + #endregion + + private void OnButtonClick(object sender, RoutedEventArgs e) + { + e.Handled = true; + this.RaiseEvent(new RoutedEventArgs(ClickEvent, this)); + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be synchronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + SplitButton button = new SplitButton(); + button.Click += ((sender, e) => this.RaiseEvent(e)); + RibbonProperties.SetSize(button, RibbonControlSize.Small); + button.CanAddButtonToQuickAccessToolBar = false; + this.BindQuickAccessItem(button); + this.BindQuickAccessItemDropDownEvents(button); + button.DropDownOpened += this.OnQuickAccessOpened; + this._quickAccessButton = button; + return button; + } + + /// + /// This method must be overridden to bind properties to use in quick access creating + /// + /// Toolbar item + protected override void BindQuickAccessItem(FrameworkElement element) + { + RibbonControl.Bind(this, element, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); + RibbonControl.Bind(this, element, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); + RibbonControl.Bind(this, element, "DropDownToolTip", DropDownToolTipProperty, BindingMode.TwoWay); + RibbonControl.Bind(this, element, "IsCheckable", IsCheckableProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "IsButtonEnabled", IsButtonEnabledProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "ContextMenu", ContextMenuProperty, BindingMode.Default); + RibbonControl.BindQuickAccessItem(this, element); + RibbonControl.Bind(this, element, "ResizeMode", ResizeModeProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.Default); + RibbonControl.Bind(this, element, "HasTriangle", HasTriangleProperty, BindingMode.Default); + } + + /// + /// Gets or sets whether button can be added to quick access toolbar + /// + public bool CanAddButtonToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddButtonToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddButtonToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddButtonToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddButtonToQuickAccessToolBarProperty = DependencyProperty.Register("CanAddButtonToQuickAccessToolBar", typeof(bool), typeof(SplitButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + private SplitButton _quickAccessButton; + + #endregion + } +} diff --git a/Fluent.Ribbon/Controls/StartScreen.cs b/Fluent.Ribbon/Controls/StartScreen.cs new file mode 100644 index 000000000..a5c34ab1e --- /dev/null +++ b/Fluent.Ribbon/Controls/StartScreen.cs @@ -0,0 +1,67 @@ +namespace Fluent +{ + using System.Windows; + + /// + /// Represents the container for the . + /// + public class StartScreen : Backstage + { + private bool previousTitleBarIsCollapsed; + + /// + /// Indicates whether the has aleaady been shown or not. + /// + public bool Shown + { + get { return (bool)this.GetValue(ShownProperty); } + set { this.SetValue(ShownProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty ShownProperty = + DependencyProperty.Register(nameof(Shown), typeof(bool), typeof(StartScreen), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null)); + + static StartScreen() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StartScreen), new FrameworkPropertyMetadata(typeof(StartScreen))); + } + + /// + /// Shows the . + /// + protected override bool Show() + { + var ribbon = this.GetParentRibbon(); + + if (ribbon?.TitleBar != null) + { + this.previousTitleBarIsCollapsed = ribbon.TitleBar.IsCollapsed; + ribbon.TitleBar.IsCollapsed = true; + } + + if (this.Shown) + { + return false; + } + + return this.Shown = base.Show(); + } + + /// + /// Hides the . + /// + protected override void Hide() + { + base.Hide(); + + var ribbon = this.GetParentRibbon(); + if (ribbon?.TitleBar != null) + { + ribbon.TitleBar.IsCollapsed = this.previousTitleBarIsCollapsed; + } + } + } +} \ No newline at end of file diff --git a/Fluent.Ribbon/Controls/StartScreenTabControl.cs b/Fluent.Ribbon/Controls/StartScreenTabControl.cs new file mode 100644 index 000000000..c1cedfd95 --- /dev/null +++ b/Fluent.Ribbon/Controls/StartScreenTabControl.cs @@ -0,0 +1,78 @@ +namespace Fluent +{ + using System.Windows; + + /// + /// Control for representing the left and right side of the start screen. + /// + public class StartScreenTabControl : BackstageTabControl + { + /// + /// Left side panel content of the startscreen. + /// + public object LeftContent + { + get { return (object)this.GetValue(LeftContentProperty); } + set { this.SetValue(LeftContentProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty LeftContentProperty = + DependencyProperty.Register(nameof(LeftContent), typeof(object), typeof(StartScreenTabControl)); + + /// + /// Right side panel content of the startscreen. + /// + public object RightContent + { + get { return (object)this.GetValue(RightContentProperty); } + set { this.SetValue(RightContentProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty RightContentProperty = + DependencyProperty.Register(nameof(RightContent), typeof(object), typeof(StartScreenTabControl)); + + /// + /// Defines the margin for + /// + public Thickness LeftContentMargin + { + get { return (Thickness)this.GetValue(LeftContentMarginProperty); } + set { this.SetValue(LeftContentMarginProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty LeftContentMarginProperty = + DependencyProperty.Register(nameof(LeftContentMargin), typeof(Thickness), typeof(StartScreenTabControl), new PropertyMetadata(default(Thickness))); + + /// + /// Defines if the is enabled in this control + /// + public bool IsWindowSteeringHelperEnabled + { + get { return (bool)this.GetValue(IsWindowSteeringHelperEnabledProperty); } + set { this.SetValue(IsWindowSteeringHelperEnabledProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty IsWindowSteeringHelperEnabledProperty = + DependencyProperty.Register(nameof(IsWindowSteeringHelperEnabled), typeof(bool), typeof(StartScreenTabControl), new PropertyMetadata(true)); + + /// + /// Static constructor. + /// + static StartScreenTabControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StartScreenTabControl), new FrameworkPropertyMetadata(typeof(StartScreenTabControl))); + } + } +} \ No newline at end of file diff --git a/Fluent/Controls/StatusBar.cs b/Fluent.Ribbon/Controls/StatusBar.cs similarity index 97% rename from Fluent/Controls/StatusBar.cs rename to Fluent.Ribbon/Controls/StatusBar.cs index c7d485e60..26ca307cb 100644 --- a/Fluent/Controls/StatusBar.cs +++ b/Fluent.Ribbon/Controls/StatusBar.cs @@ -1,354 +1,354 @@ -using System; -using System.Collections.Specialized; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Threading; - -namespace Fluent -{ - /// - /// Represents ribbon status bar - /// - public class StatusBar : System.Windows.Controls.Primitives.StatusBar - { - #region Fields - - // Context menu - private readonly ContextMenu contextMenu = new ContextMenu(); - - private Window ownerWindow; - - #endregion - - #region Properties - - /// - /// Gets or sets whether window is maximized - /// - public bool IsWindowMaximized - { - get { return (bool)this.GetValue(IsWindowMaximizedProperty); } - set { this.SetValue(IsWindowMaximizedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsWindowMaximized. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsWindowMaximizedProperty = - DependencyProperty.Register("IsWindowMaximized", typeof(bool), typeof(StatusBar), new UIPropertyMetadata(false)); - -#if NET45 - private object currentItem; -#endif - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - static StatusBar() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBar), new FrameworkPropertyMetadata(typeof(StatusBar))); - } - - /// - /// Default constructor - /// - public StatusBar() - { - this.RecreateMenu(); - this.ContextMenu = this.contextMenu; - - this.Loaded += this.OnLoaded; - this.Unloaded += this.OnUnloaded; - - this.ItemContainerGenerator.StatusChanged += this.HandleItemContainerGeneratorStatusChanged; - } - - private void OnUnloaded(object sender, RoutedEventArgs e) - { - if (this.ownerWindow != null) - { - this.ownerWindow.StateChanged -= this.OnWindowStateChanged; - this.ownerWindow = null; - } - } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - if (this.ownerWindow == null) - { - this.ownerWindow = Window.GetWindow(this); - } - - if (this.ownerWindow != null) - { - this.ownerWindow.StateChanged += this.OnWindowStateChanged; - if ((this.ownerWindow.ResizeMode == ResizeMode.CanResizeWithGrip) && (this.ownerWindow.WindowState == WindowState.Maximized)) - { - this.IsWindowMaximized = true; - } - else - { - this.IsWindowMaximized = false; - } - } - } - - private void OnWindowStateChanged(object sender, EventArgs e) - { - if ((this.ownerWindow.ResizeMode == ResizeMode.CanResizeWithGrip) && (this.ownerWindow.WindowState == WindowState.Maximized)) - { - this.IsWindowMaximized = true; - } - else - { - this.IsWindowMaximized = false; - } - } - - #endregion - - #region Overrides - - /// - /// Creates or identifies the element that is used to display the given item. - /// - /// The element that is used to display the given item. - protected override DependencyObject GetContainerForItemOverride() - { -#if NET45 - var item = this.currentItem; - this.currentItem = null; - - if (this.UsesItemContainerTemplate - && item != null) - { - var dataTemplate = this.ItemContainerTemplateSelector.SelectTemplate(item, this); - if (dataTemplate != null) - { - var dataTemplateContent = (object)dataTemplate.LoadContent(); - if (dataTemplateContent is StatusBarItem - || dataTemplateContent is Separator) - { - return dataTemplateContent as DependencyObject; - } - - throw new InvalidOperationException("Invalid ItemContainer"); - } - } -#endif - return new StatusBarItem(); - } - - /// - /// Determines if the specified item is (or is eligible to be) its own container. - /// - /// The item to check. - /// true if the item is (or is eligible to be) its own container; otherwise, false. - protected override bool IsItemItsOwnContainerOverride(object item) - { - var isItemItsOwnContainerOverride = item is StatusBarItem || item is Separator; - -#if NET45 - if (isItemItsOwnContainerOverride == false) - { - this.currentItem = item; - } -#endif - - return isItemItsOwnContainerOverride; - } - - private void HandleItemContainerGeneratorStatusChanged(object sender, EventArgs e) - { - if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) - { - return; - } - - this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (Delegate)new Action(this.RecreateMenu)); - } - - /// - /// Invoked when the property changes. - /// - /// Information about the change. - protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) - { - base.OnItemsChanged(e); - - if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) - { - return; - } - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - { - for (var i = 0; i < e.NewItems.Count; i++) - { - var container = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[i]); - var item = container as StatusBarItem; - - if (item != null) - { - item.Checked += this.OnItemChecked; - item.Unchecked += this.OnItemUnchecked; - this.contextMenu.Items.Insert(this.ItemContainerGenerator.IndexFromContainer(container), new StatusBarMenuItem(item)); - } - else - { - this.contextMenu.Items.Insert(this.ItemContainerGenerator.IndexFromContainer(container), new Separator()); - } - } - break; - } - - case NotifyCollectionChangedAction.Move: - { - for (var i = 0; i < e.NewItems.Count; i++) - { - var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1]; - this.contextMenu.Items.Remove(e.OldStartingIndex + 1); - this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, menuItem); - } - break; - } - case NotifyCollectionChangedAction.Remove: - { - for (var i = 0; i < e.OldItems.Count; i++) - { - var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1] as StatusBarMenuItem; - if (menuItem != null) - { - menuItem.StatusBarItem.Checked += this.OnItemChecked; - menuItem.StatusBarItem.Unchecked += this.OnItemUnchecked; - } - this.contextMenu.Items.RemoveAt(e.OldStartingIndex + 1); - } - break; - } - case NotifyCollectionChangedAction.Replace: - { - for (var i = 0; i < e.OldItems.Count; i++) - { - var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1] as StatusBarMenuItem; - if (menuItem != null) - { - menuItem.StatusBarItem.Checked += this.OnItemChecked; - menuItem.StatusBarItem.Unchecked += this.OnItemUnchecked; - } - - this.contextMenu.Items.RemoveAt(e.OldStartingIndex + 1); - } - - for (var i = 0; i < e.NewItems.Count; i++) - { - var item = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[i]) as StatusBarItem; - if (item != null) - { - item.Checked += this.OnItemChecked; - item.Unchecked += this.OnItemUnchecked; - this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, new StatusBarMenuItem(item)); - } - else - { - this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, new Separator()); - } - } - break; - } - case NotifyCollectionChangedAction.Reset: - { - this.RecreateMenu(); - break; - } - } - } - - private void OnItemUnchecked(object sender, RoutedEventArgs e) - { - this.UpdateSeparartorsVisibility(); - } - - private void OnItemChecked(object sender, RoutedEventArgs e) - { - this.UpdateSeparartorsVisibility(); - } - - #endregion - - #region Private Methods - - // Creates menu - private void RecreateMenu() - { - this.contextMenu.Items.Clear(); - - // Adding header separator - this.contextMenu.Items.Add(new GroupSeparatorMenuItem()); - RibbonControl.Bind(Ribbon.Localization, this.contextMenu.Items[0] as FrameworkElement, "CustomizeStatusBar", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); - - for (var i = 0; i < this.Items.Count; i++) - { - var item = this.ItemContainerGenerator.ContainerFromItem(this.Items[i]) as StatusBarItem; - if (item != null) - { - item.Checked += this.OnItemChecked; - item.Unchecked += this.OnItemUnchecked; - this.contextMenu.Items.Add(new StatusBarMenuItem(item)); - } - else - { - this.contextMenu.Items.Add(new Separator()); - } - } - - this.UpdateSeparartorsVisibility(); - } - - // Updates separators visibility, to not duplicate - private void UpdateSeparartorsVisibility() - { - var isPrevSeparator = false; - var isFirstVsible = true; - - for (var i = 0; i < this.Items.Count; i++) - { - var item = this.ItemContainerGenerator.ContainerFromItem(this.Items[i]); - var separator = item as Separator; - - if (separator != null) - { - if (isPrevSeparator || isFirstVsible) - { - separator.Visibility = Visibility.Collapsed; - } - else - { - separator.Visibility = Visibility.Visible; - } - - isPrevSeparator = true; - isFirstVsible = false; - } - else if (item is StatusBarItem) - { - if ((item as StatusBarItem).Visibility == Visibility.Visible) - { - isPrevSeparator = false; - isFirstVsible = false; - } - } - } - } - - #endregion - } +using System; +using System.Collections.Specialized; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Threading; + +namespace Fluent +{ + /// + /// Represents ribbon status bar + /// + public class StatusBar : System.Windows.Controls.Primitives.StatusBar + { + #region Fields + + // Context menu + private readonly ContextMenu contextMenu = new ContextMenu(); + + private Window ownerWindow; + + #endregion + + #region Properties + + /// + /// Gets or sets whether window is maximized + /// + public bool IsWindowMaximized + { + get { return (bool)this.GetValue(IsWindowMaximizedProperty); } + set { this.SetValue(IsWindowMaximizedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsWindowMaximized. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsWindowMaximizedProperty = + DependencyProperty.Register("IsWindowMaximized", typeof(bool), typeof(StatusBar), new UIPropertyMetadata(false)); + +#if NET45 + private object currentItem; +#endif + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + static StatusBar() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBar), new FrameworkPropertyMetadata(typeof(StatusBar))); + } + + /// + /// Default constructor + /// + public StatusBar() + { + this.RecreateMenu(); + this.ContextMenu = this.contextMenu; + + this.Loaded += this.OnLoaded; + this.Unloaded += this.OnUnloaded; + + this.ItemContainerGenerator.StatusChanged += this.HandleItemContainerGeneratorStatusChanged; + } + + private void OnUnloaded(object sender, RoutedEventArgs e) + { + if (this.ownerWindow != null) + { + this.ownerWindow.StateChanged -= this.OnWindowStateChanged; + this.ownerWindow = null; + } + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + if (this.ownerWindow == null) + { + this.ownerWindow = Window.GetWindow(this); + } + + if (this.ownerWindow != null) + { + this.ownerWindow.StateChanged += this.OnWindowStateChanged; + if ((this.ownerWindow.ResizeMode == ResizeMode.CanResizeWithGrip) && (this.ownerWindow.WindowState == WindowState.Maximized)) + { + this.IsWindowMaximized = true; + } + else + { + this.IsWindowMaximized = false; + } + } + } + + private void OnWindowStateChanged(object sender, EventArgs e) + { + if ((this.ownerWindow.ResizeMode == ResizeMode.CanResizeWithGrip) && (this.ownerWindow.WindowState == WindowState.Maximized)) + { + this.IsWindowMaximized = true; + } + else + { + this.IsWindowMaximized = false; + } + } + + #endregion + + #region Overrides + + /// + /// Creates or identifies the element that is used to display the given item. + /// + /// The element that is used to display the given item. + protected override DependencyObject GetContainerForItemOverride() + { +#if NET45 + var item = this.currentItem; + this.currentItem = null; + + if (this.UsesItemContainerTemplate + && item != null) + { + var dataTemplate = this.ItemContainerTemplateSelector.SelectTemplate(item, this); + if (dataTemplate != null) + { + var dataTemplateContent = (object)dataTemplate.LoadContent(); + if (dataTemplateContent is StatusBarItem + || dataTemplateContent is Separator) + { + return dataTemplateContent as DependencyObject; + } + + throw new InvalidOperationException("Invalid ItemContainer"); + } + } +#endif + return new StatusBarItem(); + } + + /// + /// Determines if the specified item is (or is eligible to be) its own container. + /// + /// The item to check. + /// true if the item is (or is eligible to be) its own container; otherwise, false. + protected override bool IsItemItsOwnContainerOverride(object item) + { + var isItemItsOwnContainerOverride = item is StatusBarItem || item is Separator; + +#if NET45 + if (isItemItsOwnContainerOverride == false) + { + this.currentItem = item; + } +#endif + + return isItemItsOwnContainerOverride; + } + + private void HandleItemContainerGeneratorStatusChanged(object sender, EventArgs e) + { + if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) + { + return; + } + + this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (Delegate)new Action(this.RecreateMenu)); + } + + /// + /// Invoked when the property changes. + /// + /// Information about the change. + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (this.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) + { + return; + } + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + { + for (var i = 0; i < e.NewItems.Count; i++) + { + var container = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[i]); + var item = container as StatusBarItem; + + if (item != null) + { + item.Checked += this.OnItemChecked; + item.Unchecked += this.OnItemUnchecked; + this.contextMenu.Items.Insert(this.ItemContainerGenerator.IndexFromContainer(container), new StatusBarMenuItem(item)); + } + else + { + this.contextMenu.Items.Insert(this.ItemContainerGenerator.IndexFromContainer(container), new Separator()); + } + } + break; + } + + case NotifyCollectionChangedAction.Move: + { + for (var i = 0; i < e.NewItems.Count; i++) + { + var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1]; + this.contextMenu.Items.Remove(e.OldStartingIndex + 1); + this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, menuItem); + } + break; + } + case NotifyCollectionChangedAction.Remove: + { + for (var i = 0; i < e.OldItems.Count; i++) + { + var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1] as StatusBarMenuItem; + if (menuItem != null) + { + menuItem.StatusBarItem.Checked += this.OnItemChecked; + menuItem.StatusBarItem.Unchecked += this.OnItemUnchecked; + } + this.contextMenu.Items.RemoveAt(e.OldStartingIndex + 1); + } + break; + } + case NotifyCollectionChangedAction.Replace: + { + for (var i = 0; i < e.OldItems.Count; i++) + { + var menuItem = this.contextMenu.Items[e.OldStartingIndex + 1] as StatusBarMenuItem; + if (menuItem != null) + { + menuItem.StatusBarItem.Checked += this.OnItemChecked; + menuItem.StatusBarItem.Unchecked += this.OnItemUnchecked; + } + + this.contextMenu.Items.RemoveAt(e.OldStartingIndex + 1); + } + + for (var i = 0; i < e.NewItems.Count; i++) + { + var item = this.ItemContainerGenerator.ContainerFromItem(e.NewItems[i]) as StatusBarItem; + if (item != null) + { + item.Checked += this.OnItemChecked; + item.Unchecked += this.OnItemUnchecked; + this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, new StatusBarMenuItem(item)); + } + else + { + this.contextMenu.Items.Insert(e.NewStartingIndex + i + 1, new Separator()); + } + } + break; + } + case NotifyCollectionChangedAction.Reset: + { + this.RecreateMenu(); + break; + } + } + } + + private void OnItemUnchecked(object sender, RoutedEventArgs e) + { + this.UpdateSeparartorsVisibility(); + } + + private void OnItemChecked(object sender, RoutedEventArgs e) + { + this.UpdateSeparartorsVisibility(); + } + + #endregion + + #region Private Methods + + // Creates menu + private void RecreateMenu() + { + this.contextMenu.Items.Clear(); + + // Adding header separator + this.contextMenu.Items.Add(new GroupSeparatorMenuItem()); + RibbonControl.Bind(Ribbon.Localization, this.contextMenu.Items[0] as FrameworkElement, "CustomizeStatusBar", HeaderedItemsControl.HeaderProperty, BindingMode.OneWay); + + for (var i = 0; i < this.Items.Count; i++) + { + var item = this.ItemContainerGenerator.ContainerFromItem(this.Items[i]) as StatusBarItem; + if (item != null) + { + item.Checked += this.OnItemChecked; + item.Unchecked += this.OnItemUnchecked; + this.contextMenu.Items.Add(new StatusBarMenuItem(item)); + } + else + { + this.contextMenu.Items.Add(new Separator()); + } + } + + this.UpdateSeparartorsVisibility(); + } + + // Updates separators visibility, to not duplicate + private void UpdateSeparartorsVisibility() + { + var isPrevSeparator = false; + var isFirstVsible = true; + + for (var i = 0; i < this.Items.Count; i++) + { + var item = this.ItemContainerGenerator.ContainerFromItem(this.Items[i]); + var separator = item as Separator; + + if (separator != null) + { + if (isPrevSeparator || isFirstVsible) + { + separator.Visibility = Visibility.Collapsed; + } + else + { + separator.Visibility = Visibility.Visible; + } + + isPrevSeparator = true; + isFirstVsible = false; + } + else if (item is StatusBarItem) + { + if ((item as StatusBarItem).Visibility == Visibility.Visible) + { + isPrevSeparator = false; + isFirstVsible = false; + } + } + } + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Controls/StatusBarItem.cs b/Fluent.Ribbon/Controls/StatusBarItem.cs similarity index 97% rename from Fluent/Controls/StatusBarItem.cs rename to Fluent.Ribbon/Controls/StatusBarItem.cs index 95631cdf6..832ba9259 100644 --- a/Fluent/Controls/StatusBarItem.cs +++ b/Fluent.Ribbon/Controls/StatusBarItem.cs @@ -1,159 +1,159 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls.Primitives; - -namespace Fluent -{ - /// - /// Represents ribbon status bar item - /// - public class StatusBarItem : System.Windows.Controls.Primitives.StatusBarItem - { - #region Properties - - #region Title - - /// - /// Gets or sets ribbon status bar item - /// - public string Title - { - get { return (string)this.GetValue(TitleProperty); } - set { this.SetValue(TitleProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(StatusBarItem), new UIPropertyMetadata(null)); - - #endregion - - #region Value - - /// - /// Gets or sets ribbon status bar value - /// - public string Value - { - get { return (string)this.GetValue(ValueProperty); } - set { this.SetValue(ValueProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Value. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ValueProperty = - DependencyProperty.Register("Value", typeof(string), typeof(StatusBarItem), - new UIPropertyMetadata(null, OnValueChanged)); - - static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - StatusBarItem item = (StatusBarItem)d; - item.CoerceValue(ContentProperty); - } - - - #endregion - - #region isChecked - - /// - /// Gets or sets whether status bar item is checked in menu - /// - public bool IsChecked - { - get { return (bool)this.GetValue(IsCheckedProperty); } - set { this.SetValue(IsCheckedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCheckedProperty = - DependencyProperty.Register("IsChecked", typeof(bool), typeof(StatusBarItem), new UIPropertyMetadata(true, OnIsCheckedChanged)); - - // Handles IsChecked changed - private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - StatusBarItem item = d as StatusBarItem; - item.CoerceValue(VisibilityProperty); - if((bool)e.NewValue) item.RaiseChecked(); - else item.RaiseUnchecked(); - } - - #endregion - - #endregion - - #region Events - - /// - /// Occurs when status bar item checks - /// - public event RoutedEventHandler Checked; - /// - /// Occurs when status bar item unchecks - /// - public event RoutedEventHandler Unchecked; - - // Raises checked event - private void RaiseChecked() - { - if (this.Checked != null) - this.Checked(this, new RoutedEventArgs()); - } - - // Raises unchecked event - private void RaiseUnchecked() - { - if (this.Unchecked != null) - this.Unchecked(this, new RoutedEventArgs()); - } - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - static StatusBarItem() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBarItem), new FrameworkPropertyMetadata(typeof(StatusBarItem))); - VisibilityProperty.AddOwner(typeof(StatusBarItem),new FrameworkPropertyMetadata(null, CoerceVisibility)); - ContentProperty.AddOwner(typeof (StatusBarItem), new FrameworkPropertyMetadata(null, OnContentChanged, CoerceContent)); - } - - // Content changing handler - static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - StatusBarItem item = (StatusBarItem)d; - item.CoerceValue(ValueProperty); - } - - // Coerce content - static object CoerceContent(DependencyObject d, object basevalue) - { - StatusBarItem item = (StatusBarItem)d; - // if content is null returns value - if ((basevalue == null) && (item.Value != null)) return item.Value; - return basevalue; - } - - // Coerce visibility - static object CoerceVisibility(DependencyObject d, object basevalue) - { - // If unchecked when not visible in status bar - if (!(d as StatusBarItem).IsChecked) return Visibility.Collapsed; - return basevalue; - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls.Primitives; + +namespace Fluent +{ + /// + /// Represents ribbon status bar item + /// + public class StatusBarItem : System.Windows.Controls.Primitives.StatusBarItem + { + #region Properties + + #region Title + + /// + /// Gets or sets ribbon status bar item + /// + public string Title + { + get { return (string)this.GetValue(TitleProperty); } + set { this.SetValue(TitleProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(StatusBarItem), new UIPropertyMetadata(null)); + + #endregion + + #region Value + + /// + /// Gets or sets ribbon status bar value + /// + public string Value + { + get { return (string)this.GetValue(ValueProperty); } + set { this.SetValue(ValueProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Value. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ValueProperty = + DependencyProperty.Register("Value", typeof(string), typeof(StatusBarItem), + new UIPropertyMetadata(null, OnValueChanged)); + + static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + StatusBarItem item = (StatusBarItem)d; + item.CoerceValue(ContentProperty); + } + + + #endregion + + #region isChecked + + /// + /// Gets or sets whether status bar item is checked in menu + /// + public bool IsChecked + { + get { return (bool)this.GetValue(IsCheckedProperty); } + set { this.SetValue(IsCheckedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCheckedProperty = + DependencyProperty.Register("IsChecked", typeof(bool), typeof(StatusBarItem), new UIPropertyMetadata(true, OnIsCheckedChanged)); + + // Handles IsChecked changed + private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + StatusBarItem item = d as StatusBarItem; + item.CoerceValue(VisibilityProperty); + if((bool)e.NewValue) item.RaiseChecked(); + else item.RaiseUnchecked(); + } + + #endregion + + #endregion + + #region Events + + /// + /// Occurs when status bar item checks + /// + public event RoutedEventHandler Checked; + /// + /// Occurs when status bar item unchecks + /// + public event RoutedEventHandler Unchecked; + + // Raises checked event + private void RaiseChecked() + { + if (this.Checked != null) + this.Checked(this, new RoutedEventArgs()); + } + + // Raises unchecked event + private void RaiseUnchecked() + { + if (this.Unchecked != null) + this.Unchecked(this, new RoutedEventArgs()); + } + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + static StatusBarItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBarItem), new FrameworkPropertyMetadata(typeof(StatusBarItem))); + VisibilityProperty.AddOwner(typeof(StatusBarItem),new FrameworkPropertyMetadata(null, CoerceVisibility)); + ContentProperty.AddOwner(typeof (StatusBarItem), new FrameworkPropertyMetadata(null, OnContentChanged, CoerceContent)); + } + + // Content changing handler + static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + StatusBarItem item = (StatusBarItem)d; + item.CoerceValue(ValueProperty); + } + + // Coerce content + static object CoerceContent(DependencyObject d, object basevalue) + { + StatusBarItem item = (StatusBarItem)d; + // if content is null returns value + if ((basevalue == null) && (item.Value != null)) return item.Value; + return basevalue; + } + + // Coerce visibility + static object CoerceVisibility(DependencyObject d, object basevalue) + { + // If unchecked when not visible in status bar + if (!(d as StatusBarItem).IsChecked) return Visibility.Collapsed; + return basevalue; + } + + #endregion + } +} diff --git a/Fluent/Controls/StatusBarMenuItem.cs b/Fluent.Ribbon/Controls/StatusBarMenuItem.cs similarity index 96% rename from Fluent/Controls/StatusBarMenuItem.cs rename to Fluent.Ribbon/Controls/StatusBarMenuItem.cs index f53729903..b6c4d6cfe 100644 --- a/Fluent/Controls/StatusBarMenuItem.cs +++ b/Fluent.Ribbon/Controls/StatusBarMenuItem.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using Fluent; - -namespace Fluent -{ - /// - /// Represents menu item in ribbon status bar menu - /// - public class StatusBarMenuItem : MenuItem - { - #region Properties - - /// - /// Gets or sets Ribbon Status Bar menu item - /// - public StatusBarItem StatusBarItem - { - get { return (StatusBarItem)this.GetValue(StatusBarItemProperty); } - set { this.SetValue(StatusBarItemProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for StatusBarItem. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty StatusBarItemProperty = - DependencyProperty.Register("StatusBarItem", typeof(StatusBarItem), typeof(StatusBarMenuItem), new UIPropertyMetadata(null)); - - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - static StatusBarMenuItem() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBarMenuItem), new FrameworkPropertyMetadata(typeof(StatusBarMenuItem))); - } - - /// - /// Default constructor - /// - /// Ribbon Status Bar menu item - public StatusBarMenuItem(StatusBarItem item) - { - this.StatusBarItem = item; - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using Fluent; + +namespace Fluent +{ + /// + /// Represents menu item in ribbon status bar menu + /// + public class StatusBarMenuItem : MenuItem + { + #region Properties + + /// + /// Gets or sets Ribbon Status Bar menu item + /// + public StatusBarItem StatusBarItem + { + get { return (StatusBarItem)this.GetValue(StatusBarItemProperty); } + set { this.SetValue(StatusBarItemProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for StatusBarItem. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty StatusBarItemProperty = + DependencyProperty.Register("StatusBarItem", typeof(StatusBarItem), typeof(StatusBarMenuItem), new UIPropertyMetadata(null)); + + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + static StatusBarMenuItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusBarMenuItem), new FrameworkPropertyMetadata(typeof(StatusBarMenuItem))); + } + + /// + /// Default constructor + /// + /// Ribbon Status Bar menu item + public StatusBarMenuItem(StatusBarItem item) + { + this.StatusBarItem = item; + } + + #endregion + } +} diff --git a/Fluent/Controls/StatusBarPanel.cs b/Fluent.Ribbon/Controls/StatusBarPanel.cs similarity index 97% rename from Fluent/Controls/StatusBarPanel.cs rename to Fluent.Ribbon/Controls/StatusBarPanel.cs index 54840d77b..97fbfb6de 100644 --- a/Fluent/Controls/StatusBarPanel.cs +++ b/Fluent.Ribbon/Controls/StatusBarPanel.cs @@ -1,173 +1,173 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; - -namespace Fluent -{ - /// - /// Represents panel for status bar - /// - public class StatusBarPanel: Panel - { - #region Attributes - - private List leftChildren = new List(); - private List rightChildren = new List(); - private List otherChildren = new List(); - - private int lastRightIndex = 0; - private int lastLeftIndex = 0; - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the -derived class. - /// - /// - /// The size that this element determines it needs during layout, based on its calculations of child element sizes. - /// - /// The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available. - protected override Size MeasureOverride(Size availableSize) - { - // Sort children - this.leftChildren.Clear(); - this.rightChildren.Clear(); - this.otherChildren.Clear(); - for (int i = 0; i < this.InternalChildren.Count; i++) - { - FrameworkElement child = this.InternalChildren[i] as FrameworkElement; - if (child != null) - { - if (child.HorizontalAlignment == HorizontalAlignment.Left) - this.leftChildren.Add(child); - else if (child.HorizontalAlignment == HorizontalAlignment.Right) - this.rightChildren.Add(child); - else - this.otherChildren.Add(child); - } - } - - this.lastRightIndex = this.rightChildren.Count; - this.lastLeftIndex = this.leftChildren.Count; - - // Measure children - Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); - Size zero = new Size(0, 0); - double width = 0; - double height = 0; - bool canAdd = true; - // Right children - for (int i = 0; i < this.rightChildren.Count; i++) - { - if (canAdd) - { - this.rightChildren[i].Measure(infinity); - height = Math.Max(this.rightChildren[i].DesiredSize.Height, height); - if (width + this.rightChildren[i].DesiredSize.Width <= availableSize.Width) - { - width += this.rightChildren[i].DesiredSize.Width; - } - else - { - canAdd = false; - this.rightChildren[i].Measure(zero); - this.lastRightIndex = i; - this.lastLeftIndex = 0; - } - } - else - { - this.rightChildren[i].Measure(zero); - } - } - - // Left children - for (int i = 0; i < this.leftChildren.Count; i++) - { - if (canAdd) - { - this.leftChildren[i].Measure(infinity); - height = Math.Max(this.leftChildren[i].DesiredSize.Height, height); - if (width + this.leftChildren[i].DesiredSize.Width <= availableSize.Width) - { - width += this.leftChildren[i].DesiredSize.Width; - } - else - { - canAdd = false; - this.leftChildren[i].Measure(zero); - this.lastLeftIndex = i; - - } - } - else - { - this.leftChildren[i].Measure(zero); - } - } - - // Collapse other children - for (int i = 0; i < this.otherChildren.Count; i++) - { - this.otherChildren[i].Measure(zero); - } - - return new Size(width, height); - } - - /// - /// When overridden in a derived class, positions child elements and determines a size for a derived class. - /// - /// - /// The actual size used. - /// - /// The final area within the parent that this element should use to arrange itself and its children. - protected override Size ArrangeOverride(Size finalSize) - { - Rect zero = new Rect(0, 0, 0, 0); - - // Right shift - double rightShift = 0; - // Arrange right - for (int i = this.rightChildren.Count - 1; i >= 0; i--) - { - if (this.lastRightIndex > i) - { - rightShift += this.rightChildren[i].DesiredSize.Width; - this.rightChildren[i].Arrange(new Rect(finalSize.Width - rightShift, 0, this.rightChildren[i].DesiredSize.Width, finalSize.Height)); - } - else - this.rightChildren[i].Arrange(zero); - } - - // Left shift - double leftShift = 0; - // Arrange left - for (int i = 0; i < this.leftChildren.Count; i++) - { - if (i < this.lastLeftIndex) - { - this.leftChildren[i].Arrange(new Rect(leftShift, 0, this.leftChildren[i].DesiredSize.Width, finalSize.Height)); - leftShift += this.leftChildren[i].DesiredSize.Width; - } - else - this.leftChildren[i].Arrange(zero); - } - - // Arrange other - for (int i = 0; i < this.otherChildren.Count; i++) - { - this.otherChildren[i].Arrange(zero); - } - - return finalSize; - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; + +namespace Fluent +{ + /// + /// Represents panel for status bar + /// + public class StatusBarPanel: Panel + { + #region Attributes + + private List leftChildren = new List(); + private List rightChildren = new List(); + private List otherChildren = new List(); + + private int lastRightIndex = 0; + private int lastLeftIndex = 0; + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the -derived class. + /// + /// + /// The size that this element determines it needs during layout, based on its calculations of child element sizes. + /// + /// The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available. + protected override Size MeasureOverride(Size availableSize) + { + // Sort children + this.leftChildren.Clear(); + this.rightChildren.Clear(); + this.otherChildren.Clear(); + for (int i = 0; i < this.InternalChildren.Count; i++) + { + FrameworkElement child = this.InternalChildren[i] as FrameworkElement; + if (child != null) + { + if (child.HorizontalAlignment == HorizontalAlignment.Left) + this.leftChildren.Add(child); + else if (child.HorizontalAlignment == HorizontalAlignment.Right) + this.rightChildren.Add(child); + else + this.otherChildren.Add(child); + } + } + + this.lastRightIndex = this.rightChildren.Count; + this.lastLeftIndex = this.leftChildren.Count; + + // Measure children + Size infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); + Size zero = new Size(0, 0); + double width = 0; + double height = 0; + bool canAdd = true; + // Right children + for (int i = 0; i < this.rightChildren.Count; i++) + { + if (canAdd) + { + this.rightChildren[i].Measure(infinity); + height = Math.Max(this.rightChildren[i].DesiredSize.Height, height); + if (width + this.rightChildren[i].DesiredSize.Width <= availableSize.Width) + { + width += this.rightChildren[i].DesiredSize.Width; + } + else + { + canAdd = false; + this.rightChildren[i].Measure(zero); + this.lastRightIndex = i; + this.lastLeftIndex = 0; + } + } + else + { + this.rightChildren[i].Measure(zero); + } + } + + // Left children + for (int i = 0; i < this.leftChildren.Count; i++) + { + if (canAdd) + { + this.leftChildren[i].Measure(infinity); + height = Math.Max(this.leftChildren[i].DesiredSize.Height, height); + if (width + this.leftChildren[i].DesiredSize.Width <= availableSize.Width) + { + width += this.leftChildren[i].DesiredSize.Width; + } + else + { + canAdd = false; + this.leftChildren[i].Measure(zero); + this.lastLeftIndex = i; + + } + } + else + { + this.leftChildren[i].Measure(zero); + } + } + + // Collapse other children + for (int i = 0; i < this.otherChildren.Count; i++) + { + this.otherChildren[i].Measure(zero); + } + + return new Size(width, height); + } + + /// + /// When overridden in a derived class, positions child elements and determines a size for a derived class. + /// + /// + /// The actual size used. + /// + /// The final area within the parent that this element should use to arrange itself and its children. + protected override Size ArrangeOverride(Size finalSize) + { + Rect zero = new Rect(0, 0, 0, 0); + + // Right shift + double rightShift = 0; + // Arrange right + for (int i = this.rightChildren.Count - 1; i >= 0; i--) + { + if (this.lastRightIndex > i) + { + rightShift += this.rightChildren[i].DesiredSize.Width; + this.rightChildren[i].Arrange(new Rect(finalSize.Width - rightShift, 0, this.rightChildren[i].DesiredSize.Width, finalSize.Height)); + } + else + this.rightChildren[i].Arrange(zero); + } + + // Left shift + double leftShift = 0; + // Arrange left + for (int i = 0; i < this.leftChildren.Count; i++) + { + if (i < this.lastLeftIndex) + { + this.leftChildren[i].Arrange(new Rect(leftShift, 0, this.leftChildren[i].DesiredSize.Width, finalSize.Height)); + leftShift += this.leftChildren[i].DesiredSize.Width; + } + else + this.leftChildren[i].Arrange(zero); + } + + // Arrange other + for (int i = 0; i < this.otherChildren.Count; i++) + { + this.otherChildren[i].Arrange(zero); + } + + return finalSize; + } + + #endregion + } +} diff --git a/Fluent/Controls/TextBox.cs b/Fluent.Ribbon/Controls/TextBox.cs similarity index 92% rename from Fluent/Controls/TextBox.cs rename to Fluent.Ribbon/Controls/TextBox.cs index a781cd387..60b1b33c0 100644 --- a/Fluent/Controls/TextBox.cs +++ b/Fluent.Ribbon/Controls/TextBox.cs @@ -1,755 +1,738 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Collections; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; -using System.Threading; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Threading; - -namespace Fluent -{ - /// - /// Represents custom Fluent UI TextBox - /// - [TemplatePart(Name = "PART_TextBox")] - [ContentProperty("Text")] - public class TextBox : RibbonControl - { - #region Events - - /// - /// Occurs when text is changed - /// - public event TextChangedEventHandler TextChanged; - - void RaiseTextChanged(TextChangedEventArgs args) - { - if (this.TextChanged != null) - this.TextChanged(this, args); - } - - /// - /// Occurs when selection changed - /// - public event EventHandler SelectionChanged; - - void RaiseSelectionChanged() - { - if (this.SelectionChanged != null) - this.SelectionChanged(this, EventArgs.Empty); - } - - #endregion - - #region Fields - - // TextBox in template - System.Windows.Controls.TextBox textBoxTemplated; - // Local TextBox - System.Windows.Controls.TextBox textBox = new System.Windows.Controls.TextBox(); - // Content when the textbox got focus - string textBoxContentWhenGotFocus = null; - - #endregion - - #region Properties (Dependency) - - #region InputWidth - - /// - /// Gets or sets width of the value input part of textbox - /// - public double InputWidth - { - get { return (double)this.GetValue(InputWidthProperty); } - set { this.SetValue(InputWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for InputWidth. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty InputWidthProperty = - DependencyProperty.Register("InputWidth", typeof(double), typeof(TextBox), new UIPropertyMetadata(double.NaN)); - - - #endregion - - #region Text - - /// - /// Gets or sets text content of the textbox - /// - public string Text - { - get { return (string)this.GetValue(TextProperty); } - set { this.SetValue(TextProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Content. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextProperty = - DependencyProperty.Register("Text", typeof(string), typeof(TextBox), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, - null, null, true, UpdateSourceTrigger.LostFocus)); - - #endregion - - #region IsReadOnly - - /// - /// Gets or sets whether text can be edited. This is a dependency property. - /// - public bool IsReadOnly - { - get { return (bool)this.GetValue(IsReadOnlyProperty); } - set { this.SetValue(IsReadOnlyProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsReadonly. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsReadOnlyProperty = - DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextBox), new UIPropertyMetadata(false)); - - #endregion - - #region CharacterCasing - - /// - /// Gets or sets how characters are cased - /// - public CharacterCasing CharacterCasing - { - get { return (CharacterCasing)this.GetValue(CharacterCasingProperty); } - set { this.SetValue(CharacterCasingProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CharacterCasing. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CharacterCasingProperty = - DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(TextBox), - new UIPropertyMetadata(CharacterCasing.Normal)); - - #endregion - - #region MaxLength - - /// - /// Gets or sets how many characters can be entered manually into the textbox - /// - public int MaxLength - { - get { return (int)this.GetValue(MaxLengthProperty); } - set { this.SetValue(MaxLengthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for MaxLength. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MaxLengthProperty = - DependencyProperty.Register("MaxLength", typeof(int), typeof(TextBox), new UIPropertyMetadata(int.MaxValue)); - - #endregion - - #region TextAlignment - - /// - /// Gets or sets horizontal text alignment of the content - /// - public TextAlignment TextAlignment - { - get { return (TextAlignment)this.GetValue(TextAlignmentProperty); } - set { this.SetValue(TextAlignmentProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for TextAlignment. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextAlignmentProperty = - DependencyProperty.Register("TextAlignment", typeof(TextAlignment), typeof(TextBox), - new UIPropertyMetadata(TextAlignment.Left)); - - #endregion - - #region TextDecorations - - /// - /// Gets or sets the text decorations to apply to the text box - /// - public TextDecorationCollection TextDecorations - { - get { return (TextDecorationCollection)this.GetValue(TextDecorationsProperty); } - set { this.SetValue(TextDecorationsProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for TextDecorations. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextDecorationsProperty = - DependencyProperty.Register("TextDecorations", typeof(TextDecorationCollection), typeof(TextBox), - new UIPropertyMetadata(new TextDecorationCollection())); - - #endregion - - #region IsUndoEnabled - - /// - /// Gets or sets a value that indicates whether undo support is enabled - /// - public bool IsUndoEnabled - { - get { return (bool)this.GetValue(IsUndoEnabledProperty); } - set { this.SetValue(IsUndoEnabledProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsUndoEnabled. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsUndoEnabledProperty = - DependencyProperty.Register("IsUndoEnabled", typeof(bool), typeof(TextBox), - new UIPropertyMetadata(true)); - - #endregion - - #region UndoLimit - - /// - /// Gets or sets the number of actions stored in undo queue - /// - public int UndoLimit - { - get { return (int)this.GetValue(UndoLimitProperty); } - set { this.SetValue(UndoLimitProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for UndoLimit. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty UndoLimitProperty = - DependencyProperty.Register("UndoLimit", typeof(int), typeof(TextBox), new UIPropertyMetadata(1000)); - - #endregion - - #region AutoWordSelection - - /// - /// Gets or sets whether auto word selection feature is enabled - /// - public bool AutoWordSelection - { - get { return (bool)this.GetValue(AutoWordSelectionProperty); } - set { this.SetValue(AutoWordSelectionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for AutoWordSelection. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty AutoWordSelectionProperty = - DependencyProperty.Register("AutoWordSelection", typeof(bool), typeof(TextBox), new UIPropertyMetadata(false)); - - #endregion - - #region SelectionBrush - - /// - /// Gets or sets the brush that highlights the selected text - /// - public Brush SelectionBrush - { - get { return (Brush)this.GetValue(SelectionBrushProperty); } - set { this.SetValue(SelectionBrushProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectionBrush. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectionBrushProperty = - DependencyProperty.Register("SelectionBrush", typeof(Brush), typeof(TextBox), - new UIPropertyMetadata(new SolidColorBrush(Color.FromArgb(0xFF, 0x33, 0x99, 0xFF)))); - - #endregion - - #region SelectionOpacity - - /// - /// Gets or sets opacity of the selection brush - /// - public double SelectionOpacity - { - get { return (double)this.GetValue(SelectionOpacityProperty); } - set { this.SetValue(SelectionOpacityProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SelectionOpacity. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SelectionOpacityProperty = - DependencyProperty.Register("SelectionOpacity", typeof(double), typeof(TextBox), new UIPropertyMetadata(0.4d)); - - #endregion - - #region CaretBrush - - /// - /// Gets or sets the caret brush that is used - /// to paint the caret of the text box - /// - public Brush CaretBrush - { - get { return (Brush)this.GetValue(CaretBrushProperty); } - set { this.SetValue(CaretBrushProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CaretBrush. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CaretBrushProperty = - DependencyProperty.Register("CaretBrush", typeof(Brush), typeof(TextBox), - new UIPropertyMetadata(null)); - - #endregion - - #endregion - - #region Properties - - /// - /// Gets or sets character index of the beginning of the current selection - /// - public int SelectionStart - { - get { return this.textBox.SelectionStart; } - set - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.SelectionStart = value; - else - this.textBox.SelectionStart = value; - } - } - - /// - /// Gets or sets a value that indicating the number of characters in the current selection - /// - public int SelectionLength - { - get { return this.textBox.SelectionLength; } - set - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.SelectionLength = value; - else - this.textBox.SelectionLength = value; - } - } - - /// - /// Gets or sets content of the selection - /// - public string SelectedText - { - get { return this.textBox.SelectedText; } - set - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.SelectedText = value; - else - this.textBox.SelectedText = value; - } - } - - /// - /// Gets a value that indicating whether actions can be undo - /// - public bool CanUndo - { - get { return this.textBoxTemplated == null ? false : this.textBoxTemplated.CanUndo; } - } - - /// - /// Gets a value that indicating whether actions can be redo - /// - public bool CanRedo - { - get { return this.textBoxTemplated == null ? false : this.textBoxTemplated.CanRedo; } - } - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static TextBox() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(typeof(TextBox))); - StyleProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(TextBox)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public TextBox() - { - this.Focusable = true; - this.textBox.SelectionChanged += (s, e) => this.RaiseSelectionChanged(); - this.textBox.TextChanged += (s, e) => this.RaiseTextChanged(e); - - Binding binding = new Binding("Text"); - binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; - binding.Source = this; - binding.Mode = BindingMode.TwoWay; - this.textBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, binding); - - Bind(this.textBox, this, "CharacterCasing", System.Windows.Controls.TextBox.CharacterCasingProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "MaxLength", System.Windows.Controls.TextBox.MaxLengthProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "TextAlignment", System.Windows.Controls.TextBox.TextAlignmentProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "TextDecorations", System.Windows.Controls.TextBox.TextDecorationsProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "IsUndoEnabled", TextBoxBase.IsUndoEnabledProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "UndoLimit", TextBoxBase.UndoLimitProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "AutoWordSelection", TextBoxBase.AutoWordSelectionProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "SelectionBrush", TextBoxBase.SelectionBrushProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "SelectionOpacity", TextBoxBase.SelectionOpacityProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "CaretBrush", TextBoxBase.CaretBrushProperty, BindingMode.TwoWay); - Bind(this.textBox, this, "IsReadOnly", TextBoxBase.IsReadOnlyProperty, BindingMode.TwoWay); - } - - #endregion - - #region Methods - - /// - /// Appends text - /// - /// Text - public void AppendText(string text) - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.AppendText(text); - else - this.textBox.AppendText(text); - } - - /// - /// Copies selected content to the clipboard - /// - public void Copy() - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.Copy(); - else - this.textBox.Copy(); - } - - /// - /// Cuts selected content to the clipboard - /// - public void Cut() - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.Cut(); - else - this.textBox.Cut(); - } - - /// - /// Pastes content from the clipboard - /// - public void Paste() - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.Paste(); - else - this.textBox.Paste(); - } - - /// - /// Undoes the most recent undo command - /// - /// - public bool Undo() - { - if (this.textBoxTemplated != null) return this.textBoxTemplated.Undo(); - return false; - } - - /// - /// Redoes the most recent undo command - /// - /// - public bool Redo() - { - if (this.textBoxTemplated != null) return this.textBoxTemplated.Redo(); - return false; - } - - /// - /// Selects all the contents - /// - public void SelectAll() - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.SelectAll(); - else - this.textBox.SelectAll(); - } - - /// - /// Selects contents - /// - /// Start - /// Length - public void Select(int start, int length) - { - if (this.textBoxTemplated != null) - this.textBoxTemplated.Select(start, length); - else - this.textBox.Select(start, length); - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever - /// application code or internal processes call ApplyTemplate - /// - public override void OnApplyTemplate() - { - if (this.textBoxTemplated != null) - { - this.textBoxTemplated.PreviewKeyDown -= this.OnTextBoxTemplatedKeyDown; - this.textBoxTemplated.SelectionChanged -= this.OnTextBoxTemplatedSelectionChanged; - this.textBoxTemplated.LostFocus -= this.OnTextBoxTemplatedLostFocus; - this.textBoxTemplated.GotKeyboardFocus -= this.OnTextBoxTemplatedGotKeyboardFocus; - this.textBoxTemplated.TextChanged -= this.OnTextBoxTemplatedTextChanged; - BindingOperations.ClearAllBindings(this.textBoxTemplated); - } - this.textBoxTemplated = this.GetTemplateChild("PART_TextBox") as System.Windows.Controls.TextBox; - - - // Check template - if (!this.IsTemplateValid()) - { - Debug.WriteLine("Template for TextBox control is invalid"); - return; - } - - this.textBoxTemplated.Text = this.Text; - this.textBoxTemplated.Select(this.textBox.SelectionStart, this.textBox.SelectionLength); - - // Bindings - BindingOperations.ClearAllBindings(this.textBox); - - Binding binding = new Binding("Text"); - binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; - binding.Source = this; - binding.Mode = BindingMode.TwoWay; - this.textBoxTemplated.SetBinding(System.Windows.Controls.TextBox.TextProperty, binding); - - Bind(this, this.textBoxTemplated, "CharacterCasing", System.Windows.Controls.TextBox.CharacterCasingProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "MaxLength", System.Windows.Controls.TextBox.MaxLengthProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "TextAlignment", System.Windows.Controls.TextBox.TextAlignmentProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "TextDecorations", System.Windows.Controls.TextBox.TextDecorationsProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "IsUndoEnabled", TextBoxBase.IsUndoEnabledProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "UndoLimit", TextBoxBase.UndoLimitProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "AutoWordSelection", TextBoxBase.AutoWordSelectionProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "SelectionBrush", TextBoxBase.SelectionBrushProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "SelectionOpacity", TextBoxBase.SelectionOpacityProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "CaretBrush", TextBoxBase.CaretBrushProperty, BindingMode.TwoWay); - Bind(this, this.textBoxTemplated, "IsReadOnly", TextBoxBase.IsReadOnlyProperty, BindingMode.TwoWay); - - this.textBoxTemplated.PreviewKeyDown += this.OnTextBoxTemplatedKeyDown; - this.textBoxTemplated.SelectionChanged += this.OnTextBoxTemplatedSelectionChanged; - this.textBoxTemplated.LostFocus += this.OnTextBoxTemplatedLostFocus; - this.textBoxTemplated.GotKeyboardFocus += this.OnTextBoxTemplatedGotKeyboardFocus; - this.textBoxTemplated.TextChanged += this.OnTextBoxTemplatedTextChanged; - } - - void OnTextBoxTemplatedTextChanged(object sender, TextChangedEventArgs e) - { - this.RaiseTextChanged(e); - } - - void OnTextBoxTemplatedGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - this.textBoxContentWhenGotFocus = this.textBoxTemplated.Text; - } - - void OnTextBoxTemplatedLostFocus(object sender, RoutedEventArgs e) - { - if (this.textBoxContentWhenGotFocus != this.textBoxTemplated.Text) - this.ExecuteCommand(); - } - - void OnTextBoxTemplatedSelectionChanged(object sender, RoutedEventArgs e) - { - this.textBox.Select(this.textBoxTemplated.SelectionStart, this.textBoxTemplated.SelectionLength); - } - - /// - /// Handles key tip pressed - /// - public override void OnKeyTipPressed() - { - if (!this.IsTemplateValid()) return; - - // Use dispatcher to avoid focus moving to backup'ed element - // (focused element before keytips processing) - this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, - (ThreadStart)(() => - { - this.textBoxTemplated.SelectAll(); - this.textBoxTemplated.Focus(); - })); - } - - /// - /// Invoked whenever an unhandled event reaches this element in its route. - /// - /// The that contains the event data. - protected override void OnGotFocus(RoutedEventArgs e) - { - base.OnGotFocus(e); - - if (this.textBoxTemplated != null) - { - this.textBoxTemplated.Focus(); - } - } - - /// - /// Invoked when an unhandled System.Windows.Input.Keyboard.KeyUp�attached event reaches - /// an element in its route that is derived from this class. Implement this method to add class handling for this event. - /// - /// The System.Windows.Input.KeyEventArgs that contains the event data. - protected override void OnKeyUp(KeyEventArgs e) - { - // Avoid Click invocation (from RibbonControl) - if (e.Key == Key.Enter || e.Key == Key.Space) return; - base.OnKeyUp(e); - } - - void OnTextBoxTemplatedKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Enter) - { - // Move Focus - this.textBoxTemplated.Focusable = false; - this.Focus(); - this.textBoxTemplated.Focusable = true; - } - } - - #endregion - - #region Private methods - - bool IsTemplateValid() - { - return this.textBoxTemplated != null; - } - - #endregion - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public override FrameworkElement CreateQuickAccessItem() - { - TextBox textBox = new TextBox(); - - this.BindQuickAccessItem(textBox); - - - return textBox; - } - - - /// - /// This method must be overridden to bind properties to use in quick access creating - /// - /// Toolbar item - protected void BindQuickAccessItem(FrameworkElement element) - { - RibbonControl.BindQuickAccessItem(this, element); - - TextBox textBoxQAT = (TextBox)element; - - textBoxQAT.Width = this.Width; - textBoxQAT.InputWidth = this.InputWidth; - - Bind(this, textBoxQAT, "Text", TextProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay); - Bind(this, textBoxQAT, "CharacterCasing", CharacterCasingProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "MaxLength", MaxLengthProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "TextAlignment", TextAlignmentProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "TextDecorations", TextDecorationsProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "IsUndoEnabled", IsUndoEnabledProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "UndoLimit", UndoLimitProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "AutoWordSelection", AutoWordSelectionProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "SelectionBrush", SelectionBrushProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "SelectionOpacity", SelectionOpacityProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "CaretBrush", CaretBrushProperty, BindingMode.TwoWay); - Bind(this, textBoxQAT, "IsReadOnly", IsReadOnlyProperty, BindingMode.TwoWay); - - RibbonControl.BindQuickAccessItem(this, element); - } - - #endregion - } -} +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Threading; + +namespace Fluent +{ + /// + /// Represents custom Fluent UI TextBox + /// + [TemplatePart(Name = "PART_TextBox")] + [ContentProperty("Text")] + public class TextBox : RibbonControl + { + #region Events + + /// + /// Occurs when text is changed + /// + public event TextChangedEventHandler TextChanged; + + private void RaiseTextChanged(TextChangedEventArgs args) + { + if (this.TextChanged != null) + this.TextChanged(this, args); + } + + /// + /// Occurs when selection changed + /// + public event EventHandler SelectionChanged; + + private void RaiseSelectionChanged() + { + if (this.SelectionChanged != null) + this.SelectionChanged(this, EventArgs.Empty); + } + + #endregion + + #region Fields + + // TextBox in template + private System.Windows.Controls.TextBox textBoxTemplated; + // Local TextBox + private System.Windows.Controls.TextBox textBox = new System.Windows.Controls.TextBox(); + // Content when the textbox got focus + private string textBoxContentWhenGotFocus = null; + + #endregion + + #region Properties (Dependency) + + #region InputWidth + + /// + /// Gets or sets width of the value input part of textbox + /// + public double InputWidth + { + get { return (double)this.GetValue(InputWidthProperty); } + set { this.SetValue(InputWidthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for InputWidth. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty InputWidthProperty = + DependencyProperty.Register("InputWidth", typeof(double), typeof(TextBox), new UIPropertyMetadata(double.NaN)); + + #endregion + + #region Text + + /// + /// Gets or sets text content of the textbox + /// + public string Text + { + get { return (string)this.GetValue(TextProperty); } + set { this.SetValue(TextProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Content. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(TextBox), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, + null, null, true, UpdateSourceTrigger.LostFocus)); + + #endregion + + #region IsReadOnly + + /// + /// Gets or sets whether text can be edited. This is a dependency property. + /// + public bool IsReadOnly + { + get { return (bool)this.GetValue(IsReadOnlyProperty); } + set { this.SetValue(IsReadOnlyProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsReadonly. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsReadOnlyProperty = + DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(TextBox), new UIPropertyMetadata(false)); + + #endregion + + #region CharacterCasing + + /// + /// Gets or sets how characters are cased + /// + public CharacterCasing CharacterCasing + { + get { return (CharacterCasing)this.GetValue(CharacterCasingProperty); } + set { this.SetValue(CharacterCasingProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CharacterCasing. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CharacterCasingProperty = + DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(TextBox), + new UIPropertyMetadata(CharacterCasing.Normal)); + + #endregion + + #region MaxLength + + /// + /// Gets or sets how many characters can be entered manually into the textbox + /// + public int MaxLength + { + get { return (int)this.GetValue(MaxLengthProperty); } + set { this.SetValue(MaxLengthProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for MaxLength. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty MaxLengthProperty = + DependencyProperty.Register("MaxLength", typeof(int), typeof(TextBox), new UIPropertyMetadata(int.MaxValue)); + + #endregion + + #region TextAlignment + + /// + /// Gets or sets horizontal text alignment of the content + /// + public TextAlignment TextAlignment + { + get { return (TextAlignment)this.GetValue(TextAlignmentProperty); } + set { this.SetValue(TextAlignmentProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for TextAlignment. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextAlignmentProperty = + DependencyProperty.Register("TextAlignment", typeof(TextAlignment), typeof(TextBox), + new UIPropertyMetadata(TextAlignment.Left)); + + #endregion + + #region TextDecorations + + /// + /// Gets or sets the text decorations to apply to the text box + /// + public TextDecorationCollection TextDecorations + { + get { return (TextDecorationCollection)this.GetValue(TextDecorationsProperty); } + set { this.SetValue(TextDecorationsProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for TextDecorations. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextDecorationsProperty = + DependencyProperty.Register("TextDecorations", typeof(TextDecorationCollection), typeof(TextBox), + new UIPropertyMetadata(new TextDecorationCollection())); + + #endregion + + #region IsUndoEnabled + + /// + /// Gets or sets a value that indicates whether undo support is enabled + /// + public bool IsUndoEnabled + { + get { return (bool)this.GetValue(IsUndoEnabledProperty); } + set { this.SetValue(IsUndoEnabledProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsUndoEnabled. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsUndoEnabledProperty = + DependencyProperty.Register("IsUndoEnabled", typeof(bool), typeof(TextBox), + new UIPropertyMetadata(true)); + + #endregion + + #region UndoLimit + + /// + /// Gets or sets the number of actions stored in undo queue + /// + public int UndoLimit + { + get { return (int)this.GetValue(UndoLimitProperty); } + set { this.SetValue(UndoLimitProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for UndoLimit. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty UndoLimitProperty = + DependencyProperty.Register("UndoLimit", typeof(int), typeof(TextBox), new UIPropertyMetadata(1000)); + + #endregion + + #region AutoWordSelection + + /// + /// Gets or sets whether auto word selection feature is enabled + /// + public bool AutoWordSelection + { + get { return (bool)this.GetValue(AutoWordSelectionProperty); } + set { this.SetValue(AutoWordSelectionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for AutoWordSelection. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty AutoWordSelectionProperty = + DependencyProperty.Register("AutoWordSelection", typeof(bool), typeof(TextBox), new UIPropertyMetadata(false)); + + #endregion + + #region SelectionBrush + + /// + /// Gets or sets the brush that highlights the selected text + /// + public Brush SelectionBrush + { + get { return (Brush)this.GetValue(SelectionBrushProperty); } + set { this.SetValue(SelectionBrushProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectionBrush. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectionBrushProperty = + DependencyProperty.Register("SelectionBrush", typeof(Brush), typeof(TextBox), + new UIPropertyMetadata(new SolidColorBrush(Color.FromArgb(0xFF, 0x33, 0x99, 0xFF)))); + + #endregion + + #region SelectionOpacity + + /// + /// Gets or sets opacity of the selection brush + /// + public double SelectionOpacity + { + get { return (double)this.GetValue(SelectionOpacityProperty); } + set { this.SetValue(SelectionOpacityProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SelectionOpacity. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SelectionOpacityProperty = + DependencyProperty.Register("SelectionOpacity", typeof(double), typeof(TextBox), new UIPropertyMetadata(0.4d)); + + #endregion + + #region CaretBrush + + /// + /// Gets or sets the caret brush that is used + /// to paint the caret of the text box + /// + public Brush CaretBrush + { + get { return (Brush)this.GetValue(CaretBrushProperty); } + set { this.SetValue(CaretBrushProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CaretBrush. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CaretBrushProperty = + DependencyProperty.Register("CaretBrush", typeof(Brush), typeof(TextBox), + new UIPropertyMetadata(null)); + + #endregion + + #endregion + + #region Properties + + /// + /// Gets or sets character index of the beginning of the current selection + /// + public int SelectionStart + { + get { return this.textBox.SelectionStart; } + set + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.SelectionStart = value; + else + this.textBox.SelectionStart = value; + } + } + + /// + /// Gets or sets a value that indicating the number of characters in the current selection + /// + public int SelectionLength + { + get { return this.textBox.SelectionLength; } + set + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.SelectionLength = value; + else + this.textBox.SelectionLength = value; + } + } + + /// + /// Gets or sets content of the selection + /// + public string SelectedText + { + get { return this.textBox.SelectedText; } + set + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.SelectedText = value; + else + this.textBox.SelectedText = value; + } + } + + /// + /// Gets a value that indicating whether actions can be undo + /// + public bool CanUndo + { + get { return this.textBoxTemplated == null ? false : this.textBoxTemplated.CanUndo; } + } + + /// + /// Gets a value that indicating whether actions can be redo + /// + public bool CanRedo + { + get { return this.textBoxTemplated == null ? false : this.textBoxTemplated.CanRedo; } + } + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static TextBox() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(typeof(TextBox))); + StyleProperty.OverrideMetadata(typeof(TextBox), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(TextBox)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public TextBox() + { + this.Focusable = true; + this.textBox.SelectionChanged += (s, e) => this.RaiseSelectionChanged(); + this.textBox.TextChanged += (s, e) => this.RaiseTextChanged(e); + + Binding binding = new Binding("Text"); + binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; + binding.Source = this; + binding.Mode = BindingMode.TwoWay; + this.textBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, binding); + + Bind(this.textBox, this, "CharacterCasing", System.Windows.Controls.TextBox.CharacterCasingProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "MaxLength", System.Windows.Controls.TextBox.MaxLengthProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "TextAlignment", System.Windows.Controls.TextBox.TextAlignmentProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "TextDecorations", System.Windows.Controls.TextBox.TextDecorationsProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "IsUndoEnabled", TextBoxBase.IsUndoEnabledProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "UndoLimit", TextBoxBase.UndoLimitProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "AutoWordSelection", TextBoxBase.AutoWordSelectionProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "SelectionBrush", TextBoxBase.SelectionBrushProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "SelectionOpacity", TextBoxBase.SelectionOpacityProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "CaretBrush", TextBoxBase.CaretBrushProperty, BindingMode.TwoWay); + Bind(this.textBox, this, "IsReadOnly", TextBoxBase.IsReadOnlyProperty, BindingMode.TwoWay); + } + + #endregion + + #region Methods + + /// + /// Appends text + /// + /// Text + public void AppendText(string text) + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.AppendText(text); + else + this.textBox.AppendText(text); + } + + /// + /// Copies selected content to the clipboard + /// + public void Copy() + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.Copy(); + else + this.textBox.Copy(); + } + + /// + /// Cuts selected content to the clipboard + /// + public void Cut() + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.Cut(); + else + this.textBox.Cut(); + } + + /// + /// Pastes content from the clipboard + /// + public void Paste() + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.Paste(); + else + this.textBox.Paste(); + } + + /// + /// Undoes the most recent undo command + /// + /// + public bool Undo() + { + if (this.textBoxTemplated != null) return this.textBoxTemplated.Undo(); + return false; + } + + /// + /// Redoes the most recent undo command + /// + /// + public bool Redo() + { + if (this.textBoxTemplated != null) return this.textBoxTemplated.Redo(); + return false; + } + + /// + /// Selects all the contents + /// + public void SelectAll() + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.SelectAll(); + else + this.textBox.SelectAll(); + } + + /// + /// Selects contents + /// + /// Start + /// Length + public void Select(int start, int length) + { + if (this.textBoxTemplated != null) + this.textBoxTemplated.Select(start, length); + else + this.textBox.Select(start, length); + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever + /// application code or internal processes call ApplyTemplate + /// + public override void OnApplyTemplate() + { + if (this.textBoxTemplated != null) + { + this.textBoxTemplated.PreviewKeyDown -= this.OnTextBoxTemplatedKeyDown; + this.textBoxTemplated.SelectionChanged -= this.OnTextBoxTemplatedSelectionChanged; + this.textBoxTemplated.LostFocus -= this.OnTextBoxTemplatedLostFocus; + this.textBoxTemplated.GotKeyboardFocus -= this.OnTextBoxTemplatedGotKeyboardFocus; + this.textBoxTemplated.TextChanged -= this.OnTextBoxTemplatedTextChanged; + BindingOperations.ClearAllBindings(this.textBoxTemplated); + } + this.textBoxTemplated = this.GetTemplateChild("PART_TextBox") as System.Windows.Controls.TextBox; + + + // Check template + if (!this.IsTemplateValid()) + { + Debug.WriteLine("Template for TextBox control is invalid"); + return; + } + + this.textBoxTemplated.Text = this.Text; + this.textBoxTemplated.Select(this.textBox.SelectionStart, this.textBox.SelectionLength); + + // Bindings + BindingOperations.ClearAllBindings(this.textBox); + + Binding binding = new Binding("Text"); + binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; + binding.Source = this; + binding.Mode = BindingMode.TwoWay; + this.textBoxTemplated.SetBinding(System.Windows.Controls.TextBox.TextProperty, binding); + + Bind(this, this.textBoxTemplated, "CharacterCasing", System.Windows.Controls.TextBox.CharacterCasingProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "MaxLength", System.Windows.Controls.TextBox.MaxLengthProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "TextAlignment", System.Windows.Controls.TextBox.TextAlignmentProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "TextDecorations", System.Windows.Controls.TextBox.TextDecorationsProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "IsUndoEnabled", TextBoxBase.IsUndoEnabledProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "UndoLimit", TextBoxBase.UndoLimitProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "AutoWordSelection", TextBoxBase.AutoWordSelectionProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "SelectionBrush", TextBoxBase.SelectionBrushProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "SelectionOpacity", TextBoxBase.SelectionOpacityProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "CaretBrush", TextBoxBase.CaretBrushProperty, BindingMode.TwoWay); + Bind(this, this.textBoxTemplated, "IsReadOnly", TextBoxBase.IsReadOnlyProperty, BindingMode.TwoWay); + + this.textBoxTemplated.PreviewKeyDown += this.OnTextBoxTemplatedKeyDown; + this.textBoxTemplated.SelectionChanged += this.OnTextBoxTemplatedSelectionChanged; + this.textBoxTemplated.LostFocus += this.OnTextBoxTemplatedLostFocus; + this.textBoxTemplated.GotKeyboardFocus += this.OnTextBoxTemplatedGotKeyboardFocus; + this.textBoxTemplated.TextChanged += this.OnTextBoxTemplatedTextChanged; + } + + private void OnTextBoxTemplatedTextChanged(object sender, TextChangedEventArgs e) + { + this.RaiseTextChanged(e); + } + + private void OnTextBoxTemplatedGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) + { + this.textBoxContentWhenGotFocus = this.textBoxTemplated.Text; + } + + private void OnTextBoxTemplatedLostFocus(object sender, RoutedEventArgs e) + { + if (this.textBoxContentWhenGotFocus != this.textBoxTemplated.Text) + this.ExecuteCommand(); + } + + private void OnTextBoxTemplatedSelectionChanged(object sender, RoutedEventArgs e) + { + this.textBox.Select(this.textBoxTemplated.SelectionStart, this.textBoxTemplated.SelectionLength); + } + + /// + /// Handles key tip pressed + /// + public override void OnKeyTipPressed() + { + if (!this.IsTemplateValid()) return; + + // Use dispatcher to avoid focus moving to backup'ed element + // (focused element before keytips processing) + this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, + (ThreadStart)(() => + { + this.textBoxTemplated.SelectAll(); + this.textBoxTemplated.Focus(); + })); + } + + /// + /// Invoked whenever an unhandled event reaches this element in its route. + /// + /// The that contains the event data. + protected override void OnGotFocus(RoutedEventArgs e) + { + base.OnGotFocus(e); + + if (this.textBoxTemplated != null) + { + this.textBoxTemplated.Focus(); + } + } + + /// + /// Invoked when an unhandled System.Windows.Input.Keyboard.KeyUp�attached event reaches + /// an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The System.Windows.Input.KeyEventArgs that contains the event data. + protected override void OnKeyUp(KeyEventArgs e) + { + // Avoid Click invocation (from RibbonControl) + if (e.Key == Key.Enter || e.Key == Key.Space) return; + base.OnKeyUp(e); + } + + private void OnTextBoxTemplatedKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + // Move Focus + this.textBoxTemplated.Focusable = false; + this.Focus(); + this.textBoxTemplated.Focusable = true; + } + } + + #endregion + + #region Private methods + + private bool IsTemplateValid() + { + return this.textBoxTemplated != null; + } + + #endregion + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public override FrameworkElement CreateQuickAccessItem() + { + TextBox textBox = new TextBox(); + + this.BindQuickAccessItem(textBox); + + + return textBox; + } + + /// + /// This method must be overridden to bind properties to use in quick access creating + /// + /// Toolbar item + protected void BindQuickAccessItem(FrameworkElement element) + { + RibbonControl.BindQuickAccessItem(this, element); + + TextBox textBoxQAT = (TextBox)element; + + textBoxQAT.Width = this.Width; + textBoxQAT.InputWidth = this.InputWidth; + + Bind(this, textBoxQAT, "Text", TextProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay); + Bind(this, textBoxQAT, "CharacterCasing", CharacterCasingProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "MaxLength", MaxLengthProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "TextAlignment", TextAlignmentProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "TextDecorations", TextDecorationsProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "IsUndoEnabled", IsUndoEnabledProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "UndoLimit", UndoLimitProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "AutoWordSelection", AutoWordSelectionProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "SelectionBrush", SelectionBrushProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "SelectionOpacity", SelectionOpacityProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "CaretBrush", CaretBrushProperty, BindingMode.TwoWay); + Bind(this, textBoxQAT, "IsReadOnly", IsReadOnlyProperty, BindingMode.TwoWay); + + RibbonControl.BindQuickAccessItem(this, element); + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent/Controls/ToggleButton.cs b/Fluent.Ribbon/Controls/ToggleButton.cs similarity index 93% rename from Fluent/Controls/ToggleButton.cs rename to Fluent.Ribbon/Controls/ToggleButton.cs index 32be4b5b7..16c229703 100644 --- a/Fluent/Controls/ToggleButton.cs +++ b/Fluent.Ribbon/Controls/ToggleButton.cs @@ -1,326 +1,316 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Markup; - -namespace Fluent -{ - /// - /// Represents toggle button - /// - [ContentProperty("Header")] - public class ToggleButton : System.Windows.Controls.Primitives.ToggleButton, IToggleButton, IRibbonControl, IQuickAccessItemProvider - { - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ToggleButton)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ToggleButton)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ToggleButton)); - - #endregion - - #region GroupName - - /// - /// Gets or sets the name of the group that the toggle button belongs to. - /// Use the GroupName property to specify a grouping of toggle buttons to - /// create a mutually exclusive set of controls. You can use the GroupName - /// property when only one selection is possible from a list of available - /// options. When this property is set, only one ToggleButton in the specified - /// group can be selected at a time. - /// - public string GroupName - { - get { return (string)this.GetValue(GroupNameProperty); } - set { this.SetValue(GroupNameProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupName. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupNameProperty = - DependencyProperty.Register("GroupName", typeof(string), typeof(ToggleButton), - new UIPropertyMetadata(null, ToggleButtonHelper.OnGroupNameChanged)); - - #endregion - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ToggleButton)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ToggleButton), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var element = d as ToggleButton; - - var oldElement = e.OldValue as FrameworkElement; - - if (oldElement != null) - { - element.RemoveLogicalChild(oldElement); - } - - var newElement = e.NewValue as FrameworkElement; - - if (newElement != null - && LogicalTreeHelper.GetParent(newElement) == null) - { - element.AddLogicalChild(newElement); - } - } - - #endregion - - #region LargeIcon - - /// - /// Gets or sets button large icon - /// - public object LargeIcon - { - get { return this.GetValue(LargeIconProperty); } - set { this.SetValue(LargeIconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SmallIcon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty LargeIconProperty = - DependencyProperty.Register("LargeIcon", typeof(object), - typeof(ToggleButton), new UIPropertyMetadata(null)); - - #endregion - - #region IsDefinitive - - /// - /// Gets or sets whether ribbon control click must close backstage - /// - public bool IsDefinitive - { - get { return (bool)this.GetValue(IsDefinitiveProperty); } - set { this.SetValue(IsDefinitiveProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsDefinitiveProperty = - DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(ToggleButton), new UIPropertyMetadata(true)); - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static ToggleButton() - { - Type type = typeof(ToggleButton); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - IsCheckedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(ToggleButtonHelper.OnIsCheckedChanged, ToggleButtonHelper.CoerceIsChecked)); - ContextMenuService.Attach(type); - ToolTipService.Attach(type); - StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(ToggleButton)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public ToggleButton() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region Overrides - - /// - /// Called when a is clicked. - /// - protected override void OnClick() - { - // Close popup on click - if (this.IsDefinitive) - { - PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); - } - - base.OnClick(); - } - - #endregion - - /// - /// Used to call OnClick (which is protected) - /// - public void InvokeClick() - { - this.OnClick(); - } - - #region Quick Access Item Creating - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - ToggleButton button = new ToggleButton(); - - RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); - button.Click += ((sender, e) => this.RaiseEvent(e)); - RibbonControl.BindQuickAccessItem(this, button); - - return button; - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ToggleButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Implementation of IKeyTipedControl - - /// - /// Handles key tip pressed - /// - public void OnKeyTipPressed() - { - this.OnClick(); - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - } -} +using System; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; + +namespace Fluent +{ + /// + /// Represents toggle button + /// + [ContentProperty("Header")] + public class ToggleButton : System.Windows.Controls.Primitives.ToggleButton, IToggleButton, IRibbonControl, IQuickAccessItemProvider + { + #region Properties + + #region Size + + /// + /// Gets or sets Size for the element. + /// + public RibbonControlSize Size + { + get { return (RibbonControlSize)this.GetValue(SizeProperty); } + set { this.SetValue(SizeProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Size. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ToggleButton)); + + #endregion + + #region SizeDefinition + + /// + /// Gets or sets SizeDefinition for element. + /// + public RibbonControlSizeDefinition SizeDefinition + { + get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } + set { this.SetValue(SizeDefinitionProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SizeDefinition. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ToggleButton)); + + #endregion + + #region KeyTip + + /// + /// Gets or sets KeyTip for element. + /// + public string KeyTip + { + get { return (string)this.GetValue(KeyTipProperty); } + set { this.SetValue(KeyTipProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Keys. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ToggleButton)); + + #endregion + + #region GroupName + + /// + /// Gets or sets the name of the group that the toggle button belongs to. + /// Use the GroupName property to specify a grouping of toggle buttons to + /// create a mutually exclusive set of controls. You can use the GroupName + /// property when only one selection is possible from a list of available + /// options. When this property is set, only one ToggleButton in the specified + /// group can be selected at a time. + /// + public string GroupName + { + get { return (string)this.GetValue(GroupNameProperty); } + set { this.SetValue(GroupNameProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for GroupName. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty GroupNameProperty = + DependencyProperty.Register("GroupName", typeof(string), typeof(ToggleButton), + new UIPropertyMetadata(null, ToggleButtonHelper.OnGroupNameChanged)); + + #endregion + + #region Header + + /// + /// Gets or sets element Text + /// + public object Header + { + get { return (string)this.GetValue(HeaderProperty); } + set { this.SetValue(HeaderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Header. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ToggleButton)); + + #endregion + + #region Icon + + /// + /// Gets or sets Icon for the element + /// + public object Icon + { + get { return this.GetValue(IconProperty); } + set { this.SetValue(IconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ToggleButton), new UIPropertyMetadata(null, OnIconChanged)); + + private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = d as ToggleButton; + + var oldElement = e.OldValue as FrameworkElement; + + if (oldElement != null) + { + element.RemoveLogicalChild(oldElement); + } + + var newElement = e.NewValue as FrameworkElement; + + if (newElement != null + && LogicalTreeHelper.GetParent(newElement) == null) + { + element.AddLogicalChild(newElement); + } + } + + #endregion + + #region LargeIcon + + /// + /// Gets or sets button large icon + /// + public object LargeIcon + { + get { return this.GetValue(LargeIconProperty); } + set { this.SetValue(LargeIconProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for SmallIcon. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty LargeIconProperty = + DependencyProperty.Register("LargeIcon", typeof(object), + typeof(ToggleButton), new UIPropertyMetadata(null)); + + #endregion + + #region IsDefinitive + + /// + /// Gets or sets whether ribbon control click must close backstage + /// + public bool IsDefinitive + { + get { return (bool)this.GetValue(IsDefinitiveProperty); } + set { this.SetValue(IsDefinitiveProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsDefinitive. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsDefinitiveProperty = + DependencyProperty.Register("IsDefinitive", typeof(bool), typeof(ToggleButton), new UIPropertyMetadata(true)); + + #endregion + + #endregion + + #region Constructors + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static ToggleButton() + { + Type type = typeof(ToggleButton); + DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); + IsCheckedProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(ToggleButtonHelper.OnIsCheckedChanged, ToggleButtonHelper.CoerceIsChecked)); + ContextMenuService.Attach(type); + ToolTipService.Attach(type); + StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); + } + + // Coerce object style + static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(ToggleButton)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public ToggleButton() + { + ContextMenuService.Coerce(this); + } + + #endregion + + #region Overrides + + /// + /// Called when a is clicked. + /// + protected override void OnClick() + { + // Close popup on click + if (this.IsDefinitive) + { + PopupService.RaiseDismissPopupEvent(this, DismissPopupMode.Always); + } + + base.OnClick(); + } + + #endregion + + /// + /// Used to call OnClick (which is protected) + /// + public void InvokeClick() + { + this.OnClick(); + } + + #region Quick Access Item Creating + + /// + /// Gets control which represents shortcut item. + /// This item MUST be syncronized with the original + /// and send command to original one control. + /// + /// Control which represents shortcut item + public virtual FrameworkElement CreateQuickAccessItem() + { + ToggleButton button = new ToggleButton(); + + RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay); + button.Click += ((sender, e) => this.RaiseEvent(e)); + RibbonControl.BindQuickAccessItem(this, button); + + return button; + } + + /// + /// Gets or sets whether control can be added to quick access toolbar + /// + public bool CanAddToQuickAccessToolBar + { + get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } + set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ToggleButton), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); + + #endregion + + #region Implementation of IKeyTipedControl + + /// + /// Handles key tip pressed + /// + public void OnKeyTipPressed() + { + this.OnClick(); + } + + /// + /// Handles back navigation with KeyTips + /// + public void OnKeyTipBack() + { + } + + #endregion + } +} diff --git a/Fluent/Controls/TwoLineLabel.cs b/Fluent.Ribbon/Controls/TwoLineLabel.cs similarity index 56% rename from Fluent/Controls/TwoLineLabel.cs rename to Fluent.Ribbon/Controls/TwoLineLabel.cs index 3b2f0aa76..6b7880f20 100644 --- a/Fluent/Controls/TwoLineLabel.cs +++ b/Fluent.Ribbon/Controls/TwoLineLabel.cs @@ -1,235 +1,240 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics.CodeAnalysis; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; - -namespace Fluent -{ - /// - /// Represents specific label to use in particular ribbon controls - /// - [TemplatePart(Name = "PART_TextRun", Type = typeof(TextBlock))] - [TemplatePart(Name = "PART_TextRun2", Type = typeof(TextBlock))] - [TemplatePart(Name = "PART_Glyph", Type = typeof(InlineUIContainer))] - public class TwoLineLabel: Control - { - #region Fields - - /// - /// Run with text - /// - private AccessText textRun; - - private AccessText textRun2; - - #endregion - - #region Properties - - /// - /// Gets or sets whether label must have two lines - /// - public bool HasTwoLines - { - get { return (bool)this.GetValue(HasTwoLinesProperty); } - set { this.SetValue(HasTwoLinesProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HasTwoLines. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasTwoLinesProperty = - DependencyProperty.Register("HasTwoLines", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(true,OnHasTwoLinesChanged)); - - /// - /// Handles HasTwoLines property changes - /// - /// Object - /// The event data - private static void OnHasTwoLinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as TwoLineLabel).UpdateTextRun(); - } - - /// - /// Gets or sets whether label has glyph - /// - public bool HasGlyph - { - get { return (bool)this.GetValue(HasGlyphProperty); } - set { this.SetValue(HasGlyphProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for HasGlyph. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HasGlyphProperty = - DependencyProperty.Register("HasGlyph", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(false, OnHasGlyphChanged)); - - /// - /// Handles HasGlyph property changes - /// - /// Object - /// The event data - private static void OnHasGlyphChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - (d as TwoLineLabel).UpdateTextRun(); - } - - /// - /// Gets or sets labels text - /// - public string Text - { - get { return (string)this.GetValue(TextProperty); } - set { this.SetValue(TextProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty TextProperty = - DependencyProperty.Register("Text", typeof(string), typeof(TwoLineLabel), new UIPropertyMetadata("TwoLineLabel", OnTextChanged)); - - #endregion - - #region Initialize - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static TwoLineLabel() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(typeof(TwoLineLabel))); - StyleProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle))); - } - - // Coerce object style - static object OnCoerceStyle(DependencyObject d, object basevalue) - { - if (basevalue == null) - { - basevalue = (d as FrameworkElement).TryFindResource(typeof(TwoLineLabel)); - } - - return basevalue; - } - - /// - /// Default constructor - /// - public TwoLineLabel() - { - this.Focusable = false; - } - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code or internal - /// processes call System.Windows.FrameworkElement.ApplyTemplate(). - /// - public override void OnApplyTemplate() - { - this.textRun = this.GetTemplateChild("PART_TextRun") as AccessText; - this.textRun2 = this.GetTemplateChild("PART_TextRun2") as AccessText; - this.UpdateTextRun(); - } - - #endregion - - #region Event handling - - /// - /// Handles text property changes - /// - /// Object - /// The event data - private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - TwoLineLabel label = d as TwoLineLabel; - label.UpdateTextRun(); - } - - #endregion - - #region Private methods - - /// - /// Updates text run adds newline if HasTwoLines == true - /// - void UpdateTextRun() - { - if ((this.textRun != null)&&(this.textRun2 != null)&&(this.Text != null)) - { - this.textRun.Text = this.Text; - this.textRun2.Text = ""; - string text = this.Text.Trim(); - if (this.HasTwoLines) - { - // Find soft hyphen, break at its position and display a normal hyphen. - int hyphenIndex = text.IndexOf((char)173); - if (hyphenIndex >= 0) - { - this.textRun.Text = text.Substring(0, hyphenIndex) + "-"; - this.textRun2.Text = text.Substring(hyphenIndex) + " "; - } - else - { - int centerIndex = this.Text.Length / 2; - // Find spaces nearest to center from left and right - int leftSpaceIndex = text.LastIndexOf(" ", centerIndex, centerIndex); - int rightSpaceIndex = text.IndexOf(" ", centerIndex, StringComparison.CurrentCulture); - if ((leftSpaceIndex == -1) && (rightSpaceIndex == -1)) - { - // The text can`t be separated. Add new line for glyph - //textRun.Text += '\u0085'; - } - else if (leftSpaceIndex == -1) - { - // Finds only space from right. New line adds on it - this.textRun.Text = text.Substring(0, rightSpaceIndex); - this.textRun2.Text = text.Substring(rightSpaceIndex) + " "; - } - else if (rightSpaceIndex == -1) - { - // Finds only space from left. New line adds on it - this.textRun.Text = text.Substring(0, leftSpaceIndex); - this.textRun2.Text = text.Substring(leftSpaceIndex) + " "; - } - else - { - // Find nearest to center space and add new line on it - if (Math.Abs(centerIndex - leftSpaceIndex) < Math.Abs(centerIndex - rightSpaceIndex)) - { - this.textRun.Text = text.Substring(0, leftSpaceIndex); - this.textRun2.Text = text.Substring(leftSpaceIndex) + " "; - } - else - { - this.textRun.Text = text.Substring(0, rightSpaceIndex); - this.textRun2.Text = text.Substring(rightSpaceIndex) + " "; - } - } - } - } - } - } - - #endregion - } -} +namespace Fluent +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Documents; + using System.Windows.Markup; + + /// + /// Represents specific label to use in particular ribbon controls + /// + [DefaultProperty(nameof(Text))] + [ContentProperty(nameof(Text))] + [TemplatePart(Name = "PART_TextRun", Type = typeof(TextBlock))] + [TemplatePart(Name = "PART_TextRun2", Type = typeof(TextBlock))] + [TemplatePart(Name = "PART_Glyph", Type = typeof(InlineUIContainer))] + public class TwoLineLabel : Control + { + #region Fields + + /// + /// Run with text + /// + private AccessText textRun; + + private AccessText textRun2; + + #endregion + + #region Properties + + /// + /// Gets or sets whether label must have two lines + /// + public bool HasTwoLines + { + get { return (bool)this.GetValue(HasTwoLinesProperty); } + set { this.SetValue(HasTwoLinesProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HasTwoLines. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasTwoLinesProperty = + DependencyProperty.Register("HasTwoLines", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(true, OnHasTwoLinesChanged)); + + /// + /// Handles HasTwoLines property changes + /// + /// Object + /// The event data + private static void OnHasTwoLinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((TwoLineLabel)d).UpdateTextRun(); + } + + /// + /// Gets or sets whether label has glyph + /// + public bool HasGlyph + { + get { return (bool)this.GetValue(HasGlyphProperty); } + set { this.SetValue(HasGlyphProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for HasGlyph. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty HasGlyphProperty = + DependencyProperty.Register("HasGlyph", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(false, OnHasGlyphChanged)); + + /// + /// Handles HasGlyph property changes + /// + /// Object + /// The event data + private static void OnHasGlyphChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((TwoLineLabel)d).UpdateTextRun(); + } + + /// + /// Gets or sets labels text + /// + public string Text + { + get { return (string)this.GetValue(TextProperty); } + set { this.SetValue(TextProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(TwoLineLabel), new UIPropertyMetadata(string.Empty, OnTextChanged)); + + #endregion + + #region Initialize + + /// + /// Static constructor + /// + [SuppressMessage("Microsoft.Performance", "CA1810")] + static TwoLineLabel() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(typeof(TwoLineLabel))); + StyleProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(null, OnCoerceStyle)); + } + + // Coerce object style + private static object OnCoerceStyle(DependencyObject d, object basevalue) + { + if (basevalue == null) + { + basevalue = (d as FrameworkElement).TryFindResource(typeof(TwoLineLabel)); + } + + return basevalue; + } + + /// + /// Default constructor + /// + public TwoLineLabel() + { + this.Focusable = false; + } + + #endregion + + #region Overrides + + /// + /// When overridden in a derived class, is invoked whenever application code or internal + /// processes call System.Windows.FrameworkElement.ApplyTemplate(). + /// + public override void OnApplyTemplate() + { + this.textRun = this.GetTemplateChild("PART_TextRun") as AccessText; + this.textRun2 = this.GetTemplateChild("PART_TextRun2") as AccessText; + this.UpdateTextRun(); + } + + #endregion + + #region Event handling + + /// + /// Handles text property changes + /// + /// Object + /// The event data + private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var label = (TwoLineLabel)d; + label?.UpdateTextRun(); + } + + #endregion + + #region Private methods + + /// + /// Updates text run adds newline if HasTwoLines == true + /// + private void UpdateTextRun() + { + if (this.textRun == null + || this.textRun2 == null) + { + return; + } + + if (this.HasTwoLines == false + || string.IsNullOrEmpty(this.Text)) + { + this.textRun.Text = this.Text; + this.textRun2.Text = string.Empty; + return; + } + + var text = this.Text.Trim(); + + // Find soft hyphen, break at its position and display a normal hyphen. + var hyphenIndex = text.IndexOf((char)173); + + if (hyphenIndex >= 0) + { + this.textRun.Text = text.Substring(0, hyphenIndex) + "-"; + this.textRun2.Text = text.Substring(hyphenIndex) + " "; + } + else + { + var centerIndex = this.Text.Length / 2; + // Find spaces nearest to center from left and right + var leftSpaceIndex = text.LastIndexOf(" ", centerIndex, centerIndex, StringComparison.CurrentCulture); + var rightSpaceIndex = text.IndexOf(" ", centerIndex, StringComparison.CurrentCulture); + + if (leftSpaceIndex == -1 + && rightSpaceIndex == -1) + { + this.textRun.Text = this.Text; + this.textRun2.Text = string.Empty; + } + else if (leftSpaceIndex == -1) + { + // Finds only space from right. New line adds on it + this.textRun.Text = text.Substring(0, rightSpaceIndex); + this.textRun2.Text = text.Substring(rightSpaceIndex) + " "; + } + else if (rightSpaceIndex == -1) + { + // Finds only space from left. New line adds on it + this.textRun.Text = text.Substring(0, leftSpaceIndex); + this.textRun2.Text = text.Substring(leftSpaceIndex) + " "; + } + else + { + // Find nearest to center space and add new line on it + if (Math.Abs(centerIndex - leftSpaceIndex) < Math.Abs(centerIndex - rightSpaceIndex)) + { + this.textRun.Text = text.Substring(0, leftSpaceIndex); + this.textRun2.Text = text.Substring(leftSpaceIndex) + " "; + } + else + { + this.textRun.Text = text.Substring(0, rightSpaceIndex); + this.textRun2.Text = text.Substring(rightSpaceIndex) + " "; + } + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs b/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs new file mode 100644 index 000000000..347e13048 --- /dev/null +++ b/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs @@ -0,0 +1,53 @@ +namespace Fluent +{ + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + using System.Windows.Media; + using Fluent.Helpers; + + /// + /// Helper control which enables easy embedding of window steering functions. + /// + public class WindowSteeringHelperControl : Border + { + /// + /// Static constructor + /// + static WindowSteeringHelperControl() + { + BackgroundProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(Brushes.Transparent)); + IsHitTestVisibleProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new UIPropertyMetadata(true)); + HorizontalAlignmentProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(HorizontalAlignment.Stretch)); + VerticalAlignmentProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(VerticalAlignment.Stretch)); + } + + /// + /// Invoked when an unhandled  routed event is raised on this element. Implement this method to add class handling for this event. + /// + /// The that contains the event data. The event data reports that the left mouse button was pressed. + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + if (this.IsEnabled) + { + WindowSteeringHelper.HandleMouseLeftButtonDown(e, true, true); + } + } + + /// + /// Invoked when an unhandled  routed event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. + /// + /// The that contains the event data. The event data reports that the right mouse button was released. + protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) + { + base.OnMouseRightButtonUp(e); + + if (this.IsEnabled) + { + WindowSteeringHelper.ShowSystemMenuPhysicalCoordinates(this, e); + } + } + } +} \ No newline at end of file diff --git a/Fluent/Converters/ApplicationMenuRightContentExtractorConverter.cs b/Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs similarity index 86% rename from Fluent/Converters/ApplicationMenuRightContentExtractorConverter.cs rename to Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs index 8985f7414..2fa2f6833 100644 --- a/Fluent/Converters/ApplicationMenuRightContentExtractorConverter.cs +++ b/Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs @@ -1,47 +1,47 @@ -namespace Fluent.Converters -{ - using System; - using System.Globalization; - using System.Windows.Controls; - using System.Windows.Data; - - /// - /// Extracts right content presenter of application menu converter - /// - public class ApplicationMenuRightContentExtractorConverter : IValueConverter - { - #region Implementation of IValueConverter - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var menu = value as ApplicationMenu; - if (menu != null) - { - return menu.Template.FindName("PART_RightContentPresenter", menu) as ContentPresenter; - } - - return value; - } - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value; - } - - #endregion - } +namespace Fluent.Converters +{ + using System; + using System.Globalization; + using System.Windows; + using System.Windows.Data; + + /// + /// Extracts right content presenter of application menu converter + /// + public class ApplicationMenuRightScrollViewerExtractorConverter : IValueConverter + { + #region Implementation of IValueConverter + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var menu = value as ApplicationMenu; + if (menu != null) + { + return menu.Template.FindName("PART_ScrollViewer", menu) as UIElement; + } + + return value; + } + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Converters/ColorToSolidColorBrushConverter.cs b/Fluent.Ribbon/Converters/ColorToSolidColorBrushConverter.cs similarity index 100% rename from Fluent/Converters/ColorToSolidColorBrushConverter.cs rename to Fluent.Ribbon/Converters/ColorToSolidColorBrushConverter.cs diff --git a/Fluent/Converters/IconConverter.cs b/Fluent.Ribbon/Converters/IconConverter.cs similarity index 87% rename from Fluent/Converters/IconConverter.cs rename to Fluent.Ribbon/Converters/IconConverter.cs index 65f5680b4..84e0640f3 100644 --- a/Fluent/Converters/IconConverter.cs +++ b/Fluent.Ribbon/Converters/IconConverter.cs @@ -1,141 +1,132 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Windows; -using System.Windows.Data; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Media.Imaging; - -namespace Fluent -{ - using Fluent.Metro.Native; - - /// - /// Icon converter provides default icon if user-defined is not present - /// - public sealed class IconConverter : IValueConverter - { - #region Implementation of IValueConverter - - object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - if (Application.Current != null - && Application.Current.MainWindow != null) - { - try - { - return GetDefaultIcon((new WindowInteropHelper(Application.Current.MainWindow)).Handle) as BitmapFrame; - } - catch (InvalidOperationException) - { - return null; - } - } - - var p = Process.GetCurrentProcess(); - if (p.MainWindowHandle != IntPtr.Zero) - { - return GetDefaultIcon(p.MainWindowHandle/*(new WindowInteropHelper(Application.Current.MainWindow)).Handle*/) as BitmapFrame; - } - } - - var bitmapFrame = value as BitmapFrame; - - if (bitmapFrame == null - || bitmapFrame.Decoder == null) - { - return null; - } - - foreach (var frame in bitmapFrame.Decoder.Frames) - { - var source = GetThumbnail(frame); - - if (source != null) - { - return source; - } - } - - return value; - } - - /// - /// ThumbnailExceptionWorkArround when image cause a format exception by accessing the Thumbnail - /// - /// - /// - static BitmapSource GetThumbnail(BitmapSource frame) - { - try - { - if (frame != null - && frame.PixelWidth == 16 - && frame.PixelHeight == 16 - && (frame.Format == PixelFormats.Bgra32 || frame.Format == PixelFormats.Bgr24)) - { - return frame; - } - - return null; - } - catch (Exception) - { - return null; - } - } - - [SuppressMessage("Microsoft.Design", "CA1031")] - static ImageSource GetDefaultIcon(IntPtr hwnd) - { - if (hwnd != IntPtr.Zero) - { - try - { - var zero = NativeMethods.SendMessage(hwnd, 0x7f, new IntPtr(2), IntPtr.Zero); - - if (zero == IntPtr.Zero) - { - zero = UnsafeNativeMethods.GetClassLong(hwnd, -34); - } - - if (zero == IntPtr.Zero) - { - zero = NativeMethods.LoadImage(IntPtr.Zero, new IntPtr(0x7f00), 1, (int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight, 0x8000); - } - - if (zero != IntPtr.Zero) - { - return BitmapFrame.Create(Imaging.CreateBitmapSourceFromHIcon(zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight((int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight))); - } - } - catch - { - return null; - } - } - - return null; - } - - object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return Binding.DoNothing; - } - - #endregion - } +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using System.Windows.Interop; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Fluent +{ + using Fluent.Metro.Native; + + /// + /// Icon converter provides default icon if user-defined is not present + /// + public sealed class IconConverter : IValueConverter + { + #region Implementation of IValueConverter + + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + { + if (Application.Current != null + && Application.Current.MainWindow != null) + { + try + { + return GetDefaultIcon((new WindowInteropHelper(Application.Current.MainWindow)).Handle) as BitmapFrame; + } + catch (InvalidOperationException) + { + return null; + } + } + + var p = Process.GetCurrentProcess(); + if (p.MainWindowHandle != IntPtr.Zero) + { + return GetDefaultIcon(p.MainWindowHandle/*(new WindowInteropHelper(Application.Current.MainWindow)).Handle*/) as BitmapFrame; + } + } + + var bitmapFrame = value as BitmapFrame; + + if (bitmapFrame == null + || bitmapFrame.Decoder == null) + { + return null; + } + + foreach (var frame in bitmapFrame.Decoder.Frames) + { + var source = GetThumbnail(frame); + + if (source != null) + { + return source; + } + } + + return value; + } + + /// + /// ThumbnailExceptionWorkArround when image cause a format exception by accessing the Thumbnail + /// + /// + /// + static BitmapSource GetThumbnail(BitmapSource frame) + { + try + { + if (frame != null + && frame.PixelWidth == 16 + && frame.PixelHeight == 16 + && (frame.Format == PixelFormats.Bgra32 || frame.Format == PixelFormats.Bgr24)) + { + return frame; + } + + return null; + } + catch (Exception) + { + return null; + } + } + + [SuppressMessage("Microsoft.Design", "CA1031")] + static ImageSource GetDefaultIcon(IntPtr hwnd) + { + if (hwnd != IntPtr.Zero) + { + try + { + var zero = NativeMethods.SendMessage(hwnd, 0x7f, new IntPtr(2), IntPtr.Zero); + + if (zero == IntPtr.Zero) + { + zero = NativeMethods.GetClassLong(hwnd, -34); + } + + if (zero == IntPtr.Zero) + { + zero = NativeMethods.LoadImage(IntPtr.Zero, new IntPtr(0x7f00), 1, (int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight, 0x8000); + } + + if (zero != IntPtr.Zero) + { + return BitmapFrame.Create(Imaging.CreateBitmapSourceFromHIcon(zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight((int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight))); + } + } + catch + { + return null; + } + } + + return null; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Binding.DoNothing; + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Converters/InvertNumericConverter.cs b/Fluent.Ribbon/Converters/InvertNumericConverter.cs similarity index 97% rename from Fluent/Converters/InvertNumericConverter.cs rename to Fluent.Ribbon/Converters/InvertNumericConverter.cs index ccbab4978..0f5d7a089 100644 --- a/Fluent/Converters/InvertNumericConverter.cs +++ b/Fluent.Ribbon/Converters/InvertNumericConverter.cs @@ -1,76 +1,76 @@ -namespace Fluent.Converters -{ - using System; - using System.Globalization; - using System.Windows.Data; - - /// - /// Used to invert numbers - /// - public class InvertNumericConverter : IValueConverter - { - #region Implementation of IValueConverter - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - { - var numericValue = value as float?; - - if (numericValue != null) - { - return numericValue * -1; - } - } - - { - var numericValue = value as double?; - - if (numericValue != null) - { - return numericValue * -1; - } - } - - { - var numericValue = value as int?; - - if (numericValue != null) - { - return numericValue * -1; - } - } - - { - var numericValue = value as long?; - - if (numericValue != null) - { - return numericValue * -1; - } - } - - return value; - } - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return this.Convert(value, targetType, parameter, culture); - } - - #endregion - } +namespace Fluent.Converters +{ + using System; + using System.Globalization; + using System.Windows.Data; + + /// + /// Used to invert numbers + /// + public class InvertNumericConverter : IValueConverter + { + #region Implementation of IValueConverter + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + { + var numericValue = value as float?; + + if (numericValue != null) + { + return numericValue * -1; + } + } + + { + var numericValue = value as double?; + + if (numericValue != null) + { + return numericValue * -1; + } + } + + { + var numericValue = value as int?; + + if (numericValue != null) + { + return numericValue * -1; + } + } + + { + var numericValue = value as long?; + + if (numericValue != null) + { + return numericValue * -1; + } + } + + return value; + } + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return this.Convert(value, targetType, parameter, culture); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Converters/ObjectToImageConverter.cs b/Fluent.Ribbon/Converters/ObjectToImageConverter.cs similarity index 97% rename from Fluent/Converters/ObjectToImageConverter.cs rename to Fluent.Ribbon/Converters/ObjectToImageConverter.cs index 385dcdd96..bdd5fb9dd 100644 --- a/Fluent/Converters/ObjectToImageConverter.cs +++ b/Fluent.Ribbon/Converters/ObjectToImageConverter.cs @@ -1,191 +1,191 @@ -namespace Fluent.Converters -{ - using System; - using System.Diagnostics; - using System.Globalization; - using System.Linq; - using System.Net.Cache; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Data; - using System.Windows.Media; - using System.Windows.Media.Imaging; - - /// - /// Converts string or ImageSource to Image control - /// - public class ObjectToImageConverter : IValueConverter - { - #region Implementation of IValueConverter - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var desiredSize = double.NaN; - - if (parameter != null) - { - try - { - desiredSize = System.Convert.ToDouble(parameter); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - var imagePath = value as string; - if (imagePath != null) - { - return CreateImage(imagePath, desiredSize); - } - - var imageUri = value as Uri; - if (imageUri != null) - { - return CreateImage(imageUri, desiredSize); - } - - var imageSource = value as ImageSource; - - if (imageSource == null) - { - return value; - } - - var image = new Image - { - // We have to use a frozen instance. Otherwise we run into trouble if the same instance is used in multiple locations. - // In case of BitmapImage it even gets worse when using the same Uri... - Source = (ImageSource)ExtractImage(imageSource, desiredSize).GetAsFrozen() - }; - - return image; - } - - /// - /// Converts a value. - /// - /// - /// A converted value. If the method returns null, the valid null value is used. - /// - /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return Binding.DoNothing; - } - - #endregion - - private static Image CreateImage(string imagePath, double desiredSize) - { - if (double.IsNaN(desiredSize) == false - && imagePath.EndsWith(".ico")) - { - return new Image - { - Source = ExtractImageFromIcoFile(imagePath, desiredSize) - }; - } - - return new Image - { - Source = new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute), new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)) - }; - } - private static Image CreateImage(Uri imageUri, double desiredSize) - { - if (double.IsNaN(desiredSize) == false - && imageUri.AbsolutePath.EndsWith(".ico")) - { - return new Image - { - Source = ExtractImageFromIcoFile(imageUri, desiredSize) - }; - } - - return new Image - { - Source = new BitmapImage(imageUri, new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)) - }; - } - - private static ImageSource ExtractImageFromIcoFile(string imagePath, double desiredSize) - { - return ExtractImageFromIcoFile( - new Uri("pack://application:,,," + imagePath, UriKind.RelativeOrAbsolute), - desiredSize - ); - } - - private static ImageSource ExtractImageFromIcoFile(Uri imageUri, double desiredSize) - { - var decoder = BitmapDecoder.Create( - imageUri, - BitmapCreateOptions.DelayCreation | BitmapCreateOptions.IgnoreImageCache, - BitmapCacheOption.None - ); - - return ExtractImage(decoder, desiredSize); - } - - private static ImageSource ExtractImage(ImageSource imageSource, double desiredSize) - { - if (double.IsNaN(desiredSize)) - { - return imageSource; - } - - var bitmapFrame = imageSource as BitmapFrame; - - // We may have some other type of ImageSource - // that doesn't have a notion of frames or decoder - if (bitmapFrame == null - || bitmapFrame.Decoder == null) - { - return imageSource; - } - - return ExtractImage(bitmapFrame.Decoder, desiredSize); - } - - private static ImageSource ExtractImage(BitmapDecoder decoder, double desiredSize) - { - var dpiFactor = 1.0; - - if (Application.Current.MainWindow != null) - { - // dpi.M11 = dpiX, dpi.M22 = dpiY - var presentationSource = PresentationSource.FromVisual(Application.Current.MainWindow); - - if (presentationSource != null) - { - if (presentationSource.CompositionTarget != null) - { - var dpi = presentationSource.CompositionTarget.TransformToDevice; - dpiFactor = dpi.M11; - } - } - } - - var result = decoder.Frames - .OrderBy(f => f.Width) - .FirstOrDefault(f => f.Width >= desiredSize * dpiFactor); - - // if there is no matching frame, get the largest frame - if (ReferenceEquals(result, default(BitmapFrame))) - { - result = decoder.Frames.OrderBy(f => f.Width).Last(); - } - - return result; - } - } -} +namespace Fluent.Converters +{ + using System; + using System.Diagnostics; + using System.Globalization; + using System.Linq; + using System.Net.Cache; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Data; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + /// + /// Converts string or ImageSource to Image control + /// + public class ObjectToImageConverter : IValueConverter + { + #region Implementation of IValueConverter + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var desiredSize = double.NaN; + + if (parameter != null) + { + try + { + desiredSize = System.Convert.ToDouble(parameter); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + var imagePath = value as string; + if (imagePath != null) + { + return CreateImage(imagePath, desiredSize); + } + + var imageUri = value as Uri; + if (imageUri != null) + { + return CreateImage(imageUri, desiredSize); + } + + var imageSource = value as ImageSource; + + if (imageSource == null) + { + return value; + } + + var image = new Image + { + // We have to use a frozen instance. Otherwise we run into trouble if the same instance is used in multiple locations. + // In case of BitmapImage it even gets worse when using the same Uri... + Source = (ImageSource)ExtractImage(imageSource, desiredSize).GetAsFrozen() + }; + + return image; + } + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Binding.DoNothing; + } + + #endregion + + private static Image CreateImage(string imagePath, double desiredSize) + { + if (double.IsNaN(desiredSize) == false + && imagePath.EndsWith(".ico")) + { + return new Image + { + Source = ExtractImageFromIcoFile(imagePath, desiredSize) + }; + } + + return new Image + { + Source = new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute), new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)) + }; + } + private static Image CreateImage(Uri imageUri, double desiredSize) + { + if (double.IsNaN(desiredSize) == false + && imageUri.AbsolutePath.EndsWith(".ico")) + { + return new Image + { + Source = ExtractImageFromIcoFile(imageUri, desiredSize) + }; + } + + return new Image + { + Source = new BitmapImage(imageUri, new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)) + }; + } + + private static ImageSource ExtractImageFromIcoFile(string imagePath, double desiredSize) + { + return ExtractImageFromIcoFile( + new Uri("pack://application:,,," + imagePath, UriKind.RelativeOrAbsolute), + desiredSize + ); + } + + private static ImageSource ExtractImageFromIcoFile(Uri imageUri, double desiredSize) + { + var decoder = BitmapDecoder.Create( + imageUri, + BitmapCreateOptions.DelayCreation | BitmapCreateOptions.IgnoreImageCache, + BitmapCacheOption.None + ); + + return ExtractImage(decoder, desiredSize); + } + + private static ImageSource ExtractImage(ImageSource imageSource, double desiredSize) + { + if (double.IsNaN(desiredSize)) + { + return imageSource; + } + + var bitmapFrame = imageSource as BitmapFrame; + + // We may have some other type of ImageSource + // that doesn't have a notion of frames or decoder + if (bitmapFrame == null + || bitmapFrame.Decoder == null) + { + return imageSource; + } + + return ExtractImage(bitmapFrame.Decoder, desiredSize); + } + + private static ImageSource ExtractImage(BitmapDecoder decoder, double desiredSize) + { + var dpiFactor = 1.0; + + if (Application.Current.MainWindow != null) + { + // dpi.M11 = dpiX, dpi.M22 = dpiY + var presentationSource = PresentationSource.FromVisual(Application.Current.MainWindow); + + if (presentationSource != null) + { + if (presentationSource.CompositionTarget != null) + { + var dpi = presentationSource.CompositionTarget.TransformToDevice; + dpiFactor = dpi.M11; + } + } + } + + var result = decoder.Frames + .OrderBy(f => f.Width) + .FirstOrDefault(f => f.Width >= desiredSize * dpiFactor); + + // if there is no matching frame, get the largest frame + if (ReferenceEquals(result, default(BitmapFrame))) + { + result = decoder.Frames.OrderBy(f => f.Width).Last(); + } + + return result; + } + } +} diff --git a/Fluent/Converters/SizeDefinitionConverter.cs b/Fluent.Ribbon/Converters/SizeDefinitionConverter.cs similarity index 98% rename from Fluent/Converters/SizeDefinitionConverter.cs rename to Fluent.Ribbon/Converters/SizeDefinitionConverter.cs index 9713ee0ee..739c820ca 100644 --- a/Fluent/Converters/SizeDefinitionConverter.cs +++ b/Fluent.Ribbon/Converters/SizeDefinitionConverter.cs @@ -1,36 +1,36 @@ -namespace Fluent.Converters -{ - using System; - using System.ComponentModel; - using System.Globalization; - - /// - /// Class which enables conversion from to - /// - public class SizeDefinitionConverter : TypeConverter - { - /// - /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. - /// - /// - /// true if this converter can perform the conversion; otherwise, false. - /// - /// An that provides a format context. A that represents the type you want to convert from. - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType.IsAssignableFrom(typeof(string)); - } - - /// - /// Converts the given object to the type of this converter, using the specified context and culture information. - /// - /// - /// An that represents the converted value. - /// - /// An that provides a format context. The to use as the current culture. The to convert. The conversion cannot be performed. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - return new RibbonControlSizeDefinition(value as string); - } - } +namespace Fluent.Converters +{ + using System; + using System.ComponentModel; + using System.Globalization; + + /// + /// Class which enables conversion from to + /// + public class SizeDefinitionConverter : TypeConverter + { + /// + /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. + /// + /// + /// true if this converter can perform the conversion; otherwise, false. + /// + /// An that provides a format context. A that represents the type you want to convert from. + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + return sourceType.IsAssignableFrom(typeof(string)); + } + + /// + /// Converts the given object to the type of this converter, using the specified context and culture information. + /// + /// + /// An that represents the converted value. + /// + /// An that provides a format context. The to use as the current culture. The to convert. The conversion cannot be performed. + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + return new RibbonControlSizeDefinition(value as string); + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Converters/SpinnerTextToValueConverter.cs b/Fluent.Ribbon/Converters/SpinnerTextToValueConverter.cs new file mode 100644 index 000000000..13a5a9a22 --- /dev/null +++ b/Fluent.Ribbon/Converters/SpinnerTextToValueConverter.cs @@ -0,0 +1,82 @@ +namespace Fluent.Converters +{ + using System; + using System.Globalization; + using System.Text; + using System.Windows.Data; + + /// + /// Converter class which converts from to and back. + /// + public class SpinnerTextToValueConverter : IValueConverter + { + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. + public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var converterParam = (Tuple)parameter; + var format = converterParam.Item1; + var previousValue = converterParam.Item2; + + return this.TextToDouble((string)value, format, previousValue, culture); + } + + /// + /// Converts a value. + /// + /// + /// A converted value. If the method returns null, the valid null value is used. + /// + /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return this.DoubleToText((double)value, (string)parameter, culture); + } + + /// + /// Converts the given to a . + /// + /// The value converted from or if the conversion fails. + public virtual double TextToDouble(string text, string format, double previousValue, CultureInfo culture) + { + // Remove all except digits, signs and commas + var stringBuilder = new StringBuilder(); + + foreach (var symbol in text) + { + if (char.IsDigit(symbol) || + symbol == ',' || + symbol == '.' || + (symbol == '-' && stringBuilder.Length == 0)) + { + stringBuilder.Append(symbol); + } + } + + text = stringBuilder.ToString(); + + double doubleValue; + + if (double.TryParse(text, NumberStyles.Any, culture, out doubleValue) == false) + { + doubleValue = previousValue; + } + + return doubleValue; + } + + /// + /// Converts to a formatted text using . + /// + /// converted to a . + public virtual string DoubleToText(double value, string format, CultureInfo culture) + { + return value.ToString(format, culture); + } + } +} \ No newline at end of file diff --git a/Fluent/Converters/StaticConverters.cs b/Fluent.Ribbon/Converters/StaticConverters.cs similarity index 97% rename from Fluent/Converters/StaticConverters.cs rename to Fluent.Ribbon/Converters/StaticConverters.cs index 2ffec2e79..7d83e1979 100644 --- a/Fluent/Converters/StaticConverters.cs +++ b/Fluent.Ribbon/Converters/StaticConverters.cs @@ -1,28 +1,28 @@ -namespace Fluent.Converters -{ - /// - /// Hold static instances of several commonly used converters. - /// - public static class StaticConverters - { - /// - /// Get a static instance of - /// - public static readonly InvertNumericConverter InvertNumericConverter = new InvertNumericConverter(); - - /// - /// Get a static instance of - /// - public static readonly ThicknessConverter ThicknessConverter = new ThicknessConverter(); - - /// - /// Get a static instance of - /// - public static readonly ObjectToImageConverter ObjectToImageConverter = new ObjectToImageConverter(); - - /// - /// Get a static instance of - /// - public static readonly ColorToSolidColorBrushValueConverter ColorToSolidColorBrushValueConverter = new ColorToSolidColorBrushValueConverter(); - } +namespace Fluent.Converters +{ + /// + /// Hold static instances of several commonly used converters. + /// + public static class StaticConverters + { + /// + /// Get a static instance of + /// + public static readonly InvertNumericConverter InvertNumericConverter = new InvertNumericConverter(); + + /// + /// Get a static instance of + /// + public static readonly ThicknessConverter ThicknessConverter = new ThicknessConverter(); + + /// + /// Get a static instance of + /// + public static readonly ObjectToImageConverter ObjectToImageConverter = new ObjectToImageConverter(); + + /// + /// Get a static instance of + /// + public static readonly ColorToSolidColorBrushValueConverter ColorToSolidColorBrushValueConverter = new ColorToSolidColorBrushValueConverter(); + } } \ No newline at end of file diff --git a/Fluent/Converters/ThicknessConverter.cs b/Fluent.Ribbon/Converters/ThicknessConverter.cs similarity index 98% rename from Fluent/Converters/ThicknessConverter.cs rename to Fluent.Ribbon/Converters/ThicknessConverter.cs index c79a7f2d3..93578af1d 100644 --- a/Fluent/Converters/ThicknessConverter.cs +++ b/Fluent.Ribbon/Converters/ThicknessConverter.cs @@ -1,54 +1,54 @@ -namespace Fluent.Converters -{ - using System; - using System.Globalization; - using System.Linq; - using System.Windows; - using System.Windows.Data; - - /// - /// Used to convert from four double values to - /// - public class ThicknessConverter : IMultiValueConverter - { - private static readonly System.Windows.ThicknessConverter systemThicknessConverter = new System.Windows.ThicknessConverter(); - - #region Implementation of IMultiValueConverter - - /// - /// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target. - /// - /// - /// A converted value.If the method returns null, the valid null value is used.A return value of . indicates that the converter did not produce a value, and that the binding will use the if it is available, or else will use the default value.A return value of . indicates that the binding does not transfer the value or use the or the default value. - /// - /// The array of values that the source bindings in the produces. The value indicates that the source binding has no value to provide for conversion.The type of the binding target property.The converter parameter to use.The culture to use in the converter. - public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) - { - if (values.Any(x => x == DependencyProperty.UnsetValue)) - { - if (parameter != null) - { - return (Thickness)systemThicknessConverter.ConvertFromString((string)parameter); - } - - return new Thickness(); - } - - return new Thickness(System.Convert.ToDouble(values[0]), System.Convert.ToDouble(values[1]), System.Convert.ToDouble(values[2]), System.Convert.ToDouble(values[3])); - } - - /// - /// Converts a binding target value to the source binding values. - /// - /// - /// An array of values that have been converted from the target value back to the source values. - /// - /// The value that the binding target produces.The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.The converter parameter to use.The culture to use in the converter. - public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - - #endregion - } +namespace Fluent.Converters +{ + using System; + using System.Globalization; + using System.Linq; + using System.Windows; + using System.Windows.Data; + + /// + /// Used to convert from four double values to + /// + public class ThicknessConverter : IMultiValueConverter + { + private static readonly System.Windows.ThicknessConverter systemThicknessConverter = new System.Windows.ThicknessConverter(); + + #region Implementation of IMultiValueConverter + + /// + /// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target. + /// + /// + /// A converted value.If the method returns null, the valid null value is used.A return value of . indicates that the converter did not produce a value, and that the binding will use the if it is available, or else will use the default value.A return value of . indicates that the binding does not transfer the value or use the or the default value. + /// + /// The array of values that the source bindings in the produces. The value indicates that the source binding has no value to provide for conversion.The type of the binding target property.The converter parameter to use.The culture to use in the converter. + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Any(x => x == DependencyProperty.UnsetValue)) + { + if (parameter != null) + { + return (Thickness)systemThicknessConverter.ConvertFromString((string)parameter); + } + + return new Thickness(); + } + + return new Thickness(System.Convert.ToDouble(values[0]), System.Convert.ToDouble(values[1]), System.Convert.ToDouble(values[2]), System.Convert.ToDouble(values[3])); + } + + /// + /// Converts a binding target value to the source binding values. + /// + /// + /// An array of values that have been converted from the target value back to the source values. + /// + /// The value that the binding target produces.The array of types to convert to. The array length indicates the number and types of values that are suggested for the method to return.The converter parameter to use.The culture to use in the converter. + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + #endregion + } } \ No newline at end of file diff --git a/Fluent/Documents/Features.xlsx b/Fluent.Ribbon/Documents/Features.xlsx similarity index 100% rename from Fluent/Documents/Features.xlsx rename to Fluent.Ribbon/Documents/Features.xlsx diff --git a/Fluent/Documents/Fluent Ribbon Control Suite Walkthrough.docx b/Fluent.Ribbon/Documents/Fluent Ribbon Control Suite Walkthrough.docx similarity index 100% rename from Fluent/Documents/Fluent Ribbon Control Suite Walkthrough.docx rename to Fluent.Ribbon/Documents/Fluent Ribbon Control Suite Walkthrough.docx diff --git a/Fluent/Effects/GrayscaleEffect.cs b/Fluent.Ribbon/Effects/GrayscaleEffect.cs similarity index 62% rename from Fluent/Effects/GrayscaleEffect.cs rename to Fluent.Ribbon/Effects/GrayscaleEffect.cs index 1ac427cad..0b6d321b9 100644 --- a/Fluent/Effects/GrayscaleEffect.cs +++ b/Fluent.Ribbon/Effects/GrayscaleEffect.cs @@ -1,87 +1,81 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.ComponentModel; -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Effects; - - -namespace Fluent -{ - /// - /// An effect that turns the input into shades of a single color. - /// - public class GrayscaleEffect : ShaderEffect - { - /// - /// Dependency property for Input - /// - public static readonly DependencyProperty InputProperty = - RegisterPixelShaderSamplerProperty("Input", typeof(GrayscaleEffect), 0); - - /// - /// Dependency property for FilterColor - /// - public static readonly DependencyProperty FilterColorProperty = - DependencyProperty.Register("FilterColor", typeof(Color), typeof(GrayscaleEffect), - new UIPropertyMetadata(Color.FromArgb(255, 255, 255, 255), PixelShaderConstantCallback(0))); - - /// - /// Default constructor - /// - public GrayscaleEffect() - { - var pixelShader = new PixelShader(); - var prop = DesignerProperties.IsInDesignModeProperty; - - var isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue; - if (!isInDesignMode) - { - pixelShader.UriSource = new Uri("/Fluent;component/Themes/Office2010/Effects/Grayscale.ps", UriKind.Relative); - } - - this.PixelShader = pixelShader; - - this.UpdateShaderValue(InputProperty); - this.UpdateShaderValue(FilterColorProperty); - } - - /// - /// Impicit input - /// - public Brush Input - { - get - { - return ((Brush)(this.GetValue(InputProperty))); - } - set - { - this.SetValue(InputProperty, value); - } - } - - /// - /// The color used to tint the input. - /// - public Color FilterColor - { - get - { - return ((Color)(this.GetValue(FilterColorProperty))); - } - set - { - this.SetValue(FilterColorProperty, value); - } - } - } +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Effects; + + +namespace Fluent +{ + /// + /// An effect that turns the input into shades of a single color. + /// + public class GrayscaleEffect : ShaderEffect + { + /// + /// Dependency property for Input + /// + public static readonly DependencyProperty InputProperty = + RegisterPixelShaderSamplerProperty(nameof(Input), typeof(GrayscaleEffect), 0); + + /// + /// Dependency property for FilterColor + /// + public static readonly DependencyProperty FilterColorProperty = + DependencyProperty.Register(nameof(FilterColor), typeof(Color), typeof(GrayscaleEffect), + new UIPropertyMetadata(Color.FromArgb(255, 255, 255, 255), PixelShaderConstantCallback(0))); + + /// + /// Default constructor + /// + public GrayscaleEffect() + { + this.PixelShader = this.CreatePixelShader(); + + this.UpdateShaderValue(InputProperty); + this.UpdateShaderValue(FilterColorProperty); + } + + private PixelShader CreatePixelShader() + { + var pixelShader = new PixelShader(); + + if (DesignerProperties.GetIsInDesignMode(this) == false) + { + pixelShader.UriSource = new Uri("/Fluent;component/Themes/Office2010/Effects/Grayscale.ps", UriKind.Relative); + } + + return pixelShader; + } + + /// + /// Impicit input + /// + public Brush Input + { + get + { + return (Brush)this.GetValue(InputProperty); + } + set + { + this.SetValue(InputProperty, value); + } + } + + /// + /// The color used to tint the input. + /// + public Color FilterColor + { + get + { + return (Color)this.GetValue(FilterColorProperty); + } + set + { + this.SetValue(FilterColorProperty, value); + } + } + } } \ No newline at end of file diff --git a/Fluent/Enumerations/RibbonControlSize.cs b/Fluent.Ribbon/Enumerations/RibbonControlSize.cs similarity index 95% rename from Fluent/Enumerations/RibbonControlSize.cs rename to Fluent.Ribbon/Enumerations/RibbonControlSize.cs index fe57ae5ea..b1c069935 100644 --- a/Fluent/Enumerations/RibbonControlSize.cs +++ b/Fluent.Ribbon/Enumerations/RibbonControlSize.cs @@ -1,23 +1,23 @@ -namespace Fluent -{ - /// - /// Represents logical sizes of a ribbon control - /// - public enum RibbonControlSize - { - /// - /// Large size of a control - /// - Large = 0, - - /// - /// Middle size of a control - /// - Middle, - - /// - /// Small size of a control - /// - Small - } +namespace Fluent +{ + /// + /// Represents logical sizes of a ribbon control + /// + public enum RibbonControlSize + { + /// + /// Large size of a control + /// + Large = 0, + + /// + /// Middle size of a control + /// + Middle, + + /// + /// Small size of a control + /// + Small + } } \ No newline at end of file diff --git a/Fluent/Enumerations/RibbonGroupBoxState.cs b/Fluent.Ribbon/Enumerations/RibbonGroupBoxState.cs similarity index 96% rename from Fluent/Enumerations/RibbonGroupBoxState.cs rename to Fluent.Ribbon/Enumerations/RibbonGroupBoxState.cs index fb404150a..f209b741f 100644 --- a/Fluent/Enumerations/RibbonGroupBoxState.cs +++ b/Fluent.Ribbon/Enumerations/RibbonGroupBoxState.cs @@ -1,33 +1,33 @@ -namespace Fluent -{ - /// - /// Represents states of ribbon group - /// - public enum RibbonGroupBoxState - { - /// - /// Large. All controls in the group will try to be large size - /// - Large = 0, - - /// - /// Middle. All controls in the group will try to be middle size - /// - Middle, - - /// - /// Small. All controls in the group will try to be small size - /// - Small, - - /// - /// Collapsed. Group will collapse its content in a single button - /// - Collapsed, - - /// - /// QuickAccess. Group will collapse its content in a single button in quick access toolbar - /// - QuickAccess - } +namespace Fluent +{ + /// + /// Represents states of ribbon group + /// + public enum RibbonGroupBoxState + { + /// + /// Large. All controls in the group will try to be large size + /// + Large = 0, + + /// + /// Middle. All controls in the group will try to be middle size + /// + Middle, + + /// + /// Small. All controls in the group will try to be small size + /// + Small, + + /// + /// Collapsed. Group will collapse its content in a single button + /// + Collapsed, + + /// + /// QuickAccess. Group will collapse its content in a single button in quick access toolbar + /// + QuickAccess + } } \ No newline at end of file diff --git a/Fluent/Extensibility/IRibbonSizeChangedSink.cs b/Fluent.Ribbon/Extensibility/IRibbonSizeChangedSink.cs similarity index 97% rename from Fluent/Extensibility/IRibbonSizeChangedSink.cs rename to Fluent.Ribbon/Extensibility/IRibbonSizeChangedSink.cs index 5b9d72a7b..8eeea7c2f 100644 --- a/Fluent/Extensibility/IRibbonSizeChangedSink.cs +++ b/Fluent.Ribbon/Extensibility/IRibbonSizeChangedSink.cs @@ -1,15 +1,15 @@ -namespace Fluent.Extensibility -{ - /// - /// Interface which is used to signal size changes - /// - public interface IRibbonSizeChangedSink - { - /// - /// Called when the size is changed - /// - /// Size before change - /// Size after change - void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current); - } +namespace Fluent.Extensibility +{ + /// + /// Interface which is used to signal size changes + /// + public interface IRibbonSizeChangedSink + { + /// + /// Called when the size is changed + /// + /// Size before change + /// Size after change + void OnSizePropertyChanged(RibbonControlSize previous, RibbonControlSize current); + } } \ No newline at end of file diff --git a/Fluent/Extensions/DispatcherExtensions.cs b/Fluent.Ribbon/Extensions/DispatcherExtensions.cs similarity index 96% rename from Fluent/Extensions/DispatcherExtensions.cs rename to Fluent.Ribbon/Extensions/DispatcherExtensions.cs index ccb9131ce..6320ff48f 100644 --- a/Fluent/Extensions/DispatcherExtensions.cs +++ b/Fluent.Ribbon/Extensions/DispatcherExtensions.cs @@ -1,54 +1,54 @@ -namespace Fluent.Extensions -{ - using System; - using System.Windows.Threading; - - internal static class DispatcherExtensions - { - public static void RunInDispatcherAsync(this DispatcherObject dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - if (dispatcher == null) - { - action(); - return; - } - - dispatcher.Dispatcher.RunInDispatcherAsync(action, priority); - } - - public static void RunInDispatcherAsync(this Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - if (dispatcher == null) - { - action(); - } - else - { - dispatcher.BeginInvoke(priority, action); - } - } - - public static void RunInDispatcher(this DispatcherObject dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - if (dispatcher == null) - { - action(); - return; - } - - dispatcher.Dispatcher.RunInDispatcher(action, priority); - } - - public static void RunInDispatcher(this Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) - { - if (dispatcher == null) - { - action(); - } - else - { - dispatcher.Invoke(priority, action); - } - } - } +namespace Fluent.Extensions +{ + using System; + using System.Windows.Threading; + + internal static class DispatcherExtensions + { + public static void RunInDispatcherAsync(this DispatcherObject dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) + { + action(); + return; + } + + dispatcher.Dispatcher.RunInDispatcherAsync(action, priority); + } + + public static void RunInDispatcherAsync(this Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) + { + action(); + } + else + { + dispatcher.BeginInvoke(priority, action); + } + } + + public static void RunInDispatcher(this DispatcherObject dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) + { + action(); + return; + } + + dispatcher.Dispatcher.RunInDispatcher(action, priority); + } + + public static void RunInDispatcher(this Dispatcher dispatcher, Action action, DispatcherPriority priority = DispatcherPriority.Normal) + { + if (dispatcher == null) + { + action(); + } + else + { + dispatcher.Invoke(priority, action); + } + } + } } \ No newline at end of file diff --git a/Fluent/Fluent dotNET 4.0.csproj b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj similarity index 93% rename from Fluent/Fluent dotNET 4.0.csproj rename to Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj index 9201befcb..1286a3676 100644 --- a/Fluent/Fluent dotNET 4.0.csproj +++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj @@ -1,786 +1,802 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {281095D8-D8B3-4A7F-8896-646483FB685C} - Library - Properties - Fluent - Fluent - v4.0 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - true - Properties\FluentStrongName.snk - true - 4.0.20621.0 - ..\build\obj\NET 4.0 - $(BaseIntermediateOutputPath)\$(Configuration)\ - - - true - full - false - ..\build\bin\NET 4.0\Debug\ - TRACE;DEBUG;NET40;CODE_ANALYSIS - prompt - 4 - - - false - - - MinimumRecommendedRules.ruleset - false - - - pdbonly - true - ..\build\bin\NET 4.0\Release\ - TRACE;NET40;CODE_ANALYSIS - prompt - 4 - bin\NET 4.0\Release\Fluent.XML - true - - - MinimumRecommendedRules.ruleset - true - false - - - - - - - - - - - False - ..\Lib\Net40\System.Windows.Interactivity.dll - - - False - ..\Lib\Net40\Microsoft.Windows.Shell.dll - - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SET tmpError=0 -"$(ProjectDir)Themes\XamlCombine.exe" Office2010\Generic.txt Office2010\Generic.xaml -SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -"$(ProjectDir)Themes\XamlCombine.exe" Office2013\Generic.txt Office2013\Generic.xaml -SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -"$(ProjectDir)Themes\XamlCombine.exe" Windows8\Generic.txt Windows8\Generic.xaml -SET /a tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -SET ERRORLEVEL=%25tmpError%25 - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {281095D8-D8B3-4A7F-8896-646483FB685C} + Library + Properties + Fluent + Fluent + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + true + Properties\FluentStrongName.snk + true + 4.0.20621.0 + ..\build\obj\NET 4.0 + $(BaseIntermediateOutputPath)\$(Configuration)\ + + + true + full + false + ..\build\bin\NET 4.0\Debug\ + TRACE;DEBUG;NET40;CODE_ANALYSIS + prompt + 4 + + + false + + + MinimumRecommendedRules.ruleset + false + + + pdbonly + true + ..\build\bin\NET 4.0\Release\ + TRACE;NET40;CODE_ANALYSIS + prompt + 4 + bin\NET 4.0\Release\Fluent.XML + true + + + MinimumRecommendedRules.ruleset + true + false + + + + ..\packages\ControlzEx.2.0.0.54\lib\net40\ControlzEx.dll + True + + + + + + + ..\packages\ControlzEx.2.0.0.54\lib\net40\System.Windows.Interactivity.dll + True + + + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SET tmpError=0 +"$(ProjectDir)Themes\XamlCombine.exe" Office2010\Generic.txt Office2010\Generic.xaml +SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +"$(ProjectDir)Themes\XamlCombine.exe" Office2013\Generic.txt Office2013\Generic.xaml +SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +"$(ProjectDir)Themes\XamlCombine.exe" Windows8\Generic.txt Windows8\Generic.xaml +SET /a tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +SET ERRORLEVEL=%25tmpError%25 + \ No newline at end of file diff --git a/Fluent/Fluent dotNET 4.5.csproj b/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj similarity index 93% rename from Fluent/Fluent dotNET 4.5.csproj rename to Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj index 4af4f94ba..01574d8c9 100644 --- a/Fluent/Fluent dotNET 4.5.csproj +++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj @@ -1,782 +1,802 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {4C92FCF4-3561-499F-BC5B-F2F089863047} - Library - Properties - Fluent - Fluent - v4.5 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - true - Properties\FluentStrongName.snk - true - 4.0.20621.0 - ..\build\obj\NET 4.5 - $(BaseIntermediateOutputPath)\$(Configuration)\ - - - true - full - false - ..\build\bin\NET 4.5\Debug\ - TRACE;DEBUG;CODE_ANALYSIS;NET45 - prompt - 4 - - - false - - - MinimumRecommendedRules.ruleset - false - - - pdbonly - true - ..\build\bin\NET 4.5\Release\ - TRACE;CODE_ANALYSIS;NET45 - prompt - 4 - bin\NET 4.5\Release\Fluent.XML - true - - - MinimumRecommendedRules.ruleset - true - false - - - - - - - - - - - False - ..\lib\Net45\System.Windows.Interactivity.dll - - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SET tmpError=0 -"$(ProjectDir)Themes\XamlCombine.exe" Office2010\Generic.txt Office2010\Generic.xaml -SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -"$(ProjectDir)Themes\XamlCombine.exe" Office2013\Generic.txt Office2013\Generic.xaml -SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -"$(ProjectDir)Themes\XamlCombine.exe" Windows8\Generic.txt Windows8\Generic.xaml -SET /a tmpError=%25tmpError%25 + %25ERRORLEVEL%25 -SET ERRORLEVEL=%25tmpError%25 - + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {4C92FCF4-3561-499F-BC5B-F2F089863047} + Library + Properties + Fluent + Fluent + v4.5 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + true + Properties\FluentStrongName.snk + true + 4.0.20621.0 + ..\build\obj\NET 4.5 + $(BaseIntermediateOutputPath)\$(Configuration)\ + + + true + full + false + ..\build\bin\NET 4.5\Debug\ + TRACE;DEBUG;CODE_ANALYSIS;NET45 + prompt + 4 + + + false + + + MinimumRecommendedRules.ruleset + false + + + pdbonly + true + ..\build\bin\NET 4.5\Release\ + TRACE;CODE_ANALYSIS;NET45 + prompt + 4 + bin\NET 4.5\Release\Fluent.XML + true + + + MinimumRecommendedRules.ruleset + true + false + + + + ..\packages\ControlzEx.2.0.0.54\lib\net45\ControlzEx.dll + True + + + + + + + ..\packages\ControlzEx.2.0.0.54\lib\net45\System.Windows.Interactivity.dll + True + + + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SET tmpError=0 +"$(ProjectDir)Themes\XamlCombine.exe" Office2010\Generic.txt Office2010\Generic.xaml +SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +"$(ProjectDir)Themes\XamlCombine.exe" Office2013\Generic.txt Office2013\Generic.xaml +SET tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +"$(ProjectDir)Themes\XamlCombine.exe" Windows8\Generic.txt Windows8\Generic.xaml +SET /a tmpError=%25tmpError%25 + %25ERRORLEVEL%25 +SET ERRORLEVEL=%25tmpError%25 + \ No newline at end of file diff --git a/Fluent/Helpers/FrameworkHelper.cs b/Fluent.Ribbon/Helpers/FrameworkHelper.cs similarity index 97% rename from Fluent/Helpers/FrameworkHelper.cs rename to Fluent.Ribbon/Helpers/FrameworkHelper.cs index 693d28e93..f72b62c7d 100644 --- a/Fluent/Helpers/FrameworkHelper.cs +++ b/Fluent.Ribbon/Helpers/FrameworkHelper.cs @@ -1,52 +1,52 @@ -namespace Fluent -{ - using System; - using System.Reflection; - using System.Windows; - using System.Windows.Media; - - /// - /// Represents class to determine .NET Framework version difference - /// - public static class FrameworkHelper - { - /// - /// Version of WPF - /// - public static readonly Version PresentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; - - /// - /// Gets UseLayoutRounding attached property value - /// - /// - /// - public static bool GetUseLayoutRounding(DependencyObject obj) - { - return (bool)obj.GetValue(UseLayoutRoundingProperty); - } - - /// - /// Gets UseLayoutRounding attached property value - /// - /// - /// - public static void SetUseLayoutRounding(DependencyObject obj, bool value) - { - obj.SetValue(UseLayoutRoundingProperty, value); - } - - /// - /// Using a DependencyProperty as the backing store for UseLayoutRounding. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty UseLayoutRoundingProperty = - DependencyProperty.RegisterAttached("UseLayoutRounding", typeof(bool), typeof(FrameworkHelper), new UIPropertyMetadata(false, OnUseLayoutRoundingChanged)); - - private static void OnUseLayoutRoundingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - d.SetValue(UIElement.SnapsToDevicePixelsProperty, true); - RenderOptions.SetClearTypeHint(d, ClearTypeHint.Enabled); - d.SetValue(FrameworkElement.UseLayoutRoundingProperty, true); - } - - } +namespace Fluent +{ + using System; + using System.Reflection; + using System.Windows; + using System.Windows.Media; + + /// + /// Represents class to determine .NET Framework version difference + /// + public static class FrameworkHelper + { + /// + /// Version of WPF + /// + public static readonly Version PresentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + + /// + /// Gets UseLayoutRounding attached property value + /// + /// + /// + public static bool GetUseLayoutRounding(DependencyObject obj) + { + return (bool)obj.GetValue(UseLayoutRoundingProperty); + } + + /// + /// Gets UseLayoutRounding attached property value + /// + /// + /// + public static void SetUseLayoutRounding(DependencyObject obj, bool value) + { + obj.SetValue(UseLayoutRoundingProperty, value); + } + + /// + /// Using a DependencyProperty as the backing store for UseLayoutRounding. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty UseLayoutRoundingProperty = + DependencyProperty.RegisterAttached("UseLayoutRounding", typeof(bool), typeof(FrameworkHelper), new UIPropertyMetadata(false, OnUseLayoutRoundingChanged)); + + private static void OnUseLayoutRoundingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.SetValue(UIElement.SnapsToDevicePixelsProperty, true); + RenderOptions.SetClearTypeHint(d, ClearTypeHint.Enabled); + d.SetValue(FrameworkElement.UseLayoutRoundingProperty, true); + } + + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Helpers/PoupHelper.cs b/Fluent.Ribbon/Helpers/PoupHelper.cs new file mode 100644 index 000000000..312f0cdfd --- /dev/null +++ b/Fluent.Ribbon/Helpers/PoupHelper.cs @@ -0,0 +1,52 @@ +namespace Fluent.Helpers +{ + using System.Windows; + using System.Windows.Controls.Primitives; + + /// + /// Helper class to position . + /// + public static class PopupHelper + { + /// + /// Positions like would but ignores the value of . + /// + public static CustomPopupPlacementCallback SimplePlacementCallback => GetSimplePlacement; + + /// + /// Gets the values for a like would but ignores the value of . + /// + public static CustomPopupPlacement[] GetSimplePlacement(Size popupSize, Size targetSize, Point offset) + { + // Create placements which should never cover the target + return new[] + { + new CustomPopupPlacement + { + Point = new Point(0, 0), + PrimaryAxis = PopupPrimaryAxis.None + }, + new CustomPopupPlacement + { + Point = new Point(-popupSize.Width, 0), + PrimaryAxis = PopupPrimaryAxis.Horizontal + }, + new CustomPopupPlacement + { + Point = new Point(0, -popupSize.Height - targetSize.Height), + PrimaryAxis = PopupPrimaryAxis.Vertical + }, + new CustomPopupPlacement + { + Point = new Point(-popupSize.Width, -popupSize.Height), + PrimaryAxis = PopupPrimaryAxis.Vertical + }, + new CustomPopupPlacement + { + Point = new Point(targetSize.Width, -popupSize.Height), + PrimaryAxis = PopupPrimaryAxis.Horizontal + } + }; + } + } +} \ No newline at end of file diff --git a/Fluent/Helpers/ToggleButtonHelper.cs b/Fluent.Ribbon/Helpers/ToggleButtonHelper.cs similarity index 53% rename from Fluent/Helpers/ToggleButtonHelper.cs rename to Fluent.Ribbon/Helpers/ToggleButtonHelper.cs index ab911d899..cb930a07b 100644 --- a/Fluent/Helpers/ToggleButtonHelper.cs +++ b/Fluent.Ribbon/Helpers/ToggleButtonHelper.cs @@ -1,146 +1,215 @@ -namespace Fluent -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Windows; - - /// - /// Helper-Class for switching states in ToggleButton-Groups - /// - public class ToggleButtonHelper - { - // Grouped buttons - private static readonly Dictionary> groupedButtons = new Dictionary>(); - - /// - /// Handles changes to - /// - public static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var toggleButton = (IToggleButton)d; - var currentGroupName = (string)e.NewValue; - var previousGroupName = (string)e.OldValue; - - if (previousGroupName != null) - { - RemoveFromGroup(previousGroupName, toggleButton); - } - - if (currentGroupName != null) - { - AddToGroup(currentGroupName, toggleButton); - } - } - - /// - /// Coerce - /// - public static object CoerceIsChecked(DependencyObject d, object basevalue) - { - var toggleButton = (IToggleButton)d; - - // If the button does not belong to any group - // or the button/control is not loaded - // we don't have to do any checks and can directly return the requested basevalue - if (toggleButton.GroupName == null - || toggleButton.IsLoaded == false) - { - return basevalue; - } - - var baseIsChecked = (bool?)basevalue; - - if (baseIsChecked.HasValue == false - || baseIsChecked.Value == false) - { - var buttons = GetButtonsInGroup(toggleButton.GroupName); - - // We can not allow that there is no button checked - foreach (var item in buttons) - { - // It's Ok, atleast one checked button exists - // and it's not the current button - if (ReferenceEquals(item, toggleButton) == false - && item.IsChecked == true) - { - return basevalue; - } - } - - // This button can not be unchecked - return true; - } - - return basevalue; - } - - /// - /// Handles changes to - /// - public static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var newValue = (bool?)e.NewValue; - var button = (IToggleButton)d; - - // Uncheck other toggle buttons - if (!newValue.HasValue || !newValue.Value || button.GroupName == null) - { - return; - } - - var buttons = GetButtonsInGroup(button.GroupName); - - foreach (var item in buttons.Where(item => item != button)) - { - item.IsChecked = false; - } - } - - /// - /// Remove from group - /// - private static void RemoveFromGroup(string groupName, IToggleButton toggleButton) - { - List buttons; - - if (!groupedButtons.TryGetValue(groupName, out buttons)) - { - return; - } - - buttons.RemoveAt(buttons.FindIndex(x => (x.IsAlive && ((IToggleButton)x.Target) == toggleButton))); - } - - /// - /// Add to group - /// - private static void AddToGroup(string groupName, IToggleButton toggleButton) - { - List buttons; - - if (!groupedButtons.TryGetValue(groupName, out buttons)) - { - buttons = new List(); - groupedButtons.Add(groupName, buttons); - } - - buttons.Add(new WeakReference(toggleButton)); - } - - /// - /// Gets all buttons in the given group - /// - private static IEnumerable GetButtonsInGroup(string groupName) - { - List buttons; - - if (!groupedButtons.TryGetValue(groupName, out buttons)) - { - return new List(); - } - - return buttons.Where(x => x.IsAlive).Select(x => (IToggleButton)x.Target).ToList(); - } - } +namespace Fluent +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Windows; + using System.Windows.Media; + + /// + /// Helper-Class for switching states in ToggleButton-Groups + /// + public class ToggleButtonHelper + { + // Grouped buttons + [ThreadStatic] + private static Dictionary> groupedButtons; + + private static Dictionary> GroupedButtons + { + get { return groupedButtons ?? (groupedButtons = new Dictionary>()); } + } + + /// + /// Handles changes to + /// + public static void OnGroupNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var toggleButton = (IToggleButton)d; + var currentGroupName = (string)e.NewValue; + var previousGroupName = (string)e.OldValue; + + if (previousGroupName != null) + { + RemoveFromGroup(previousGroupName, toggleButton); + } + + if (currentGroupName != null) + { + AddToGroup(currentGroupName, toggleButton); + } + } + + /// + /// Coerce + /// + public static object CoerceIsChecked(DependencyObject d, object basevalue) + { + var toggleButton = (IToggleButton)d; + + // If the button does not belong to any group + // or the button/control is not loaded + // we don't have to do any checks and can directly return the requested basevalue + if (toggleButton.GroupName == null + || toggleButton.IsLoaded == false) + { + return basevalue; + } + + var baseIsChecked = (bool?)basevalue; + + if (baseIsChecked.HasValue == false + || baseIsChecked.Value == false) + { + var buttons = GetButtonsInGroup(toggleButton); + + // We can not allow that there is no button checked + foreach (var item in buttons) + { + // It's Ok, atleast one checked button exists + // and it's not the current button + if (ReferenceEquals(item, toggleButton) == false + && item.IsChecked == true) + { + return basevalue; + } + } + + // This button can not be unchecked + return true; + } + + return basevalue; + } + + /// + /// Handles changes to + /// + public static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var newValue = (bool?)e.NewValue; + var button = (IToggleButton)d; + + // Uncheck other toggle buttons + if (newValue.HasValue == false + || newValue.Value == false + || button.GroupName == null) + { + return; + } + + List buttons; + + if (GroupedButtons.TryGetValue(button.GroupName, out buttons) == false) + { + return; + } + + var rootScope = PresentationSource.FromVisual((Visual)button); + + // Get all elements bound to this key and remove this element + for (var i = 0; i < buttons.Count;) + { + var weakReference = buttons[i]; + var currentButton = weakReference.Target as IToggleButton; + if (currentButton == null) + { + // Remove dead instances + buttons.RemoveAt(i); + } + else + { + // Uncheck all checked RadioButtons different from the current one + if (currentButton != button + && currentButton.IsChecked == true + && rootScope == PresentationSource.FromVisual((Visual)currentButton)) + { + currentButton.IsChecked = false; + } + + i++; + } + } + } + + /// + /// Remove from group + /// + private static void RemoveFromGroup(string groupName, IToggleButton toggleButton) + { + List buttons; + + if (GroupedButtons.TryGetValue(groupName, out buttons) == false) + { + return; + } + + PurgeDead(buttons, toggleButton); + + if (buttons.Count == 0) + { + GroupedButtons.Remove(groupName); + } + } + + /// + /// Add to group + /// + private static void AddToGroup(string groupName, IToggleButton toggleButton) + { + List buttons; + + if (GroupedButtons.TryGetValue(groupName, out buttons) == false) + { + buttons = new List(); + GroupedButtons.Add(groupName, buttons); + } + else + { + PurgeDead(buttons, null); + } + + buttons.Add(new WeakReference(toggleButton)); + } + + /// + /// Gets all buttons in the given group + /// + private static IEnumerable GetButtonsInGroup(IToggleButton button) + { + List buttons; + + if (GroupedButtons.TryGetValue(button.GroupName, out buttons) == false) + { + return Enumerable.Empty(); + } + + PurgeDead(buttons, null); + + var rootScope = PresentationSource.FromVisual((Visual)button); + + return buttons + .Where(x => rootScope == PresentationSource.FromVisual((Visual)x.Target)) + .Select(x => (IToggleButton)x.Target).ToList(); + } + + private static void PurgeDead(List elements, object elementToRemove) + { + for (var i = 0; i < elements.Count;) + { + var weakReference = elements[i]; + var element = weakReference.Target; + + if (element == null + || element == elementToRemove) + { + elements.RemoveAt(i); + } + else + { + i++; + } + } + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Helpers/WindowSteeringHelper.cs b/Fluent.Ribbon/Helpers/WindowSteeringHelper.cs new file mode 100644 index 000000000..509139341 --- /dev/null +++ b/Fluent.Ribbon/Helpers/WindowSteeringHelper.cs @@ -0,0 +1,119 @@ +namespace Fluent.Helpers +{ + using System; + using System.Windows; + using System.Windows.Input; + using System.Windows.Interop; + using Fluent.Metro.Native; + + /// + /// Class which offers helper methods for steering the window + /// + public static class WindowSteeringHelper + { + /// + /// Shows the system menu at the current mouse position. + /// + /// The mouse event args. + /// Defines if window dragging should be handled. + /// Defines if window state changes should be handled. + public static void HandleMouseLeftButtonDown(MouseButtonEventArgs e, bool handleDragMove, bool handleStateChange) + { + var dependencyObject = e.Source as DependencyObject; + + if (dependencyObject == null) + { + return; + } + + HandleMouseLeftButtonDown(dependencyObject, e, handleDragMove, handleStateChange); + } + + /// + /// Shows the system menu at the current mouse position. + /// + /// The object which was the source of the mouse event. + /// The mouse event args. + /// Defines if window dragging should be handled. + /// Defines if window state changes should be handled. + public static void HandleMouseLeftButtonDown(DependencyObject dependencyObject, MouseButtonEventArgs e, bool handleDragMove, bool handleStateChange) + { + var window = Window.GetWindow(dependencyObject); + + if (window == null) + { + return; + } + + if (handleDragMove && e.ClickCount == 1) + { + e.Handled = true; + window.DragMove(); + } + else if (handleStateChange && + e.ClickCount == 2 && + window.ResizeMode != ResizeMode.NoResize) + { + e.Handled = true; + window.WindowState = window.WindowState == WindowState.Maximized + ? WindowState.Normal + : WindowState.Maximized; + } + } + + /// + /// Shows the system menu at the current mouse position. + /// + /// The object which was the source of the mouse event. + /// The mouse event args. + public static void ShowSystemMenuPhysicalCoordinates(DependencyObject dependencyObject, MouseButtonEventArgs e) + { + var window = Window.GetWindow(dependencyObject); + + if (window == null) + { + return; + } + + ShowSystemMenuPhysicalCoordinates(window, e); + } + + /// + /// Shows the system menu at the current mouse position. + /// + /// The window for which the system menu should be shown. + /// The mouse event args. + public static void ShowSystemMenuPhysicalCoordinates(Window window, MouseButtonEventArgs e) + { + var mousePosition = e.GetPosition(window); + var physicalScreenLocation = window.PointToScreen(mousePosition); + ShowSystemMenuPhysicalCoordinates(window, e, physicalScreenLocation); + } + + /// + /// Shows the system menu at . + /// + /// The window for which the system menu should be shown. + /// The mouse event args. + /// The location at which the system menu should be shown. + public static void ShowSystemMenuPhysicalCoordinates(Window window, MouseButtonEventArgs e, Point physicalScreenLocation) + { + var hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero + || NativeMethods.IsWindow(hwnd) == false) + { + return; + } + + e.Handled = true; + + var hmenu = NativeMethods.GetSystemMenu(hwnd, false); + + var cmd = NativeMethods.TrackPopupMenuEx(hmenu, Constants.TPM_LEFTBUTTON | Constants.TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero); + if (0 != cmd) + { + NativeMethods.PostMessage(hwnd, Constants.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero); + } + } + } +} \ No newline at end of file diff --git a/Fluent/IDropDownControl.cs b/Fluent.Ribbon/IDropDownControl.cs similarity index 96% rename from Fluent/IDropDownControl.cs rename to Fluent.Ribbon/IDropDownControl.cs index 6253cb2b6..fda743bf9 100644 --- a/Fluent/IDropDownControl.cs +++ b/Fluent.Ribbon/IDropDownControl.cs @@ -1,25 +1,25 @@ -namespace Fluent -{ - using System.Windows.Controls.Primitives; - - /// - /// Represents control that have drop down popup - /// - public interface IDropDownControl - { - /// - /// Gets drop down popup - /// - Popup DropDownPopup { get; } - - /// - /// Gets a value indicating whether control context menu is opened - /// - bool IsContextMenuOpened { get; set; } - - /// - /// Gets or sets a value indicating whether drop down is opened - /// - bool IsDropDownOpen { get; set; } - } +namespace Fluent +{ + using System.Windows.Controls.Primitives; + + /// + /// Represents control that have drop down popup + /// + public interface IDropDownControl + { + /// + /// Gets drop down popup + /// + Popup DropDownPopup { get; } + + /// + /// Gets a value indicating whether control context menu is opened + /// + bool IsContextMenuOpened { get; set; } + + /// + /// Gets or sets a value indicating whether drop down is opened + /// + bool IsDropDownOpen { get; set; } + } } \ No newline at end of file diff --git a/Fluent/IHeaderedControl.cs b/Fluent.Ribbon/IHeaderedControl.cs similarity index 100% rename from Fluent/IHeaderedControl.cs rename to Fluent.Ribbon/IHeaderedControl.cs diff --git a/Fluent/IKeyTipedControl.cs b/Fluent.Ribbon/IKeyTipedControl.cs similarity index 96% rename from Fluent/IKeyTipedControl.cs rename to Fluent.Ribbon/IKeyTipedControl.cs index bd2217ec4..8ad6f5d01 100644 --- a/Fluent/IKeyTipedControl.cs +++ b/Fluent.Ribbon/IKeyTipedControl.cs @@ -1,23 +1,23 @@ -namespace Fluent -{ - /// - /// Base interface for controls supports key tips - /// - public interface IKeyTipedControl - { - /// - /// Get and sets KeyTip for element. - /// - string KeyTip { get; set; } - - /// - /// Handles key tip pressed - /// - void OnKeyTipPressed(); - - /// - /// Handles back navigation with KeyTips - /// - void OnKeyTipBack(); - } +namespace Fluent +{ + /// + /// Base interface for controls supports key tips + /// + public interface IKeyTipedControl + { + /// + /// Get and sets KeyTip for element. + /// + string KeyTip { get; set; } + + /// + /// Handles key tip pressed + /// + void OnKeyTipPressed(); + + /// + /// Handles back navigation with KeyTips + /// + void OnKeyTipBack(); + } } \ No newline at end of file diff --git a/Fluent/IRibbonControl.cs b/Fluent.Ribbon/IRibbonControl.cs similarity index 96% rename from Fluent/IRibbonControl.cs rename to Fluent.Ribbon/IRibbonControl.cs index 25567d275..d3dee5eda 100644 --- a/Fluent/IRibbonControl.cs +++ b/Fluent.Ribbon/IRibbonControl.cs @@ -1,23 +1,23 @@ -namespace Fluent -{ - /// - /// Base interface for Fluent controls - /// - public interface IRibbonControl : IHeaderedControl, IKeyTipedControl - { - /// - /// Gets or sets Size for the element - /// - RibbonControlSize Size { get; set; } - - /// - /// Gets or sets SizeDefinition for element - /// - RibbonControlSizeDefinition SizeDefinition { get; set; } - - /// - /// Gets or sets Icon for the element - /// - object Icon { get; set; } - } +namespace Fluent +{ + /// + /// Base interface for Fluent controls + /// + public interface IRibbonControl : IHeaderedControl, IKeyTipedControl + { + /// + /// Gets or sets Size for the element + /// + RibbonControlSize Size { get; set; } + + /// + /// Gets or sets SizeDefinition for element + /// + RibbonControlSizeDefinition SizeDefinition { get; set; } + + /// + /// Gets or sets Icon for the element + /// + object Icon { get; set; } + } } \ No newline at end of file diff --git a/Fluent/IScalableRibbonControl.cs b/Fluent.Ribbon/IScalableRibbonControl.cs similarity index 54% rename from Fluent/IScalableRibbonControl.cs rename to Fluent.Ribbon/IScalableRibbonControl.cs index d4700ad86..b6caa493e 100644 --- a/Fluent/IScalableRibbonControl.cs +++ b/Fluent.Ribbon/IScalableRibbonControl.cs @@ -1,33 +1,24 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; - -namespace Fluent -{ - /// - /// Repesents scalable ribbon contol - /// - public interface IScalableRibbonControl - { - /// - /// Enlarge control size - /// - void Enlarge(); - /// - /// Reduce control size - /// - void Reduce(); - - /// - /// Occurs when contol is scaled - /// - event EventHandler Scaled; - } -} +using System; + +namespace Fluent +{ + /// + /// Repesents scalable ribbon contol + /// + public interface IScalableRibbonControl + { + /// + /// Enlarge control size + /// + void Enlarge(); + /// + /// Reduce control size + /// + void Reduce(); + + /// + /// Occurs when contol is scaled + /// + event EventHandler Scaled; + } +} diff --git a/Fluent/IToggleButton.cs b/Fluent.Ribbon/IToggleButton.cs similarity index 97% rename from Fluent/IToggleButton.cs rename to Fluent.Ribbon/IToggleButton.cs index 4d918d83a..d7176ab7c 100644 --- a/Fluent/IToggleButton.cs +++ b/Fluent.Ribbon/IToggleButton.cs @@ -1,28 +1,28 @@ -namespace Fluent -{ - /// - /// Interface for controls that support -Behavior - /// - public interface IToggleButton - { - /// - /// Gets or sets the name of the group that the toggle button belongs to. - /// Use the GroupName property to specify a grouping of toggle buttons to - /// create a mutually exclusive set of controls. You can use the GroupName - /// property when only one selection is possible from a list of available - /// options. When this property is set, only one ToggleButton in the specified - /// group can be selected at a time. - /// - string GroupName { get; set; } - - /// - /// Gets or sets a value indicating whether SplitButton is checked - /// - bool? IsChecked { get; set; } - - /// - /// Gets a value that indicates whether the ToggleButton is fully loaded - /// - bool IsLoaded { get; } - } +namespace Fluent +{ + /// + /// Interface for controls that support -Behavior + /// + public interface IToggleButton + { + /// + /// Gets or sets the name of the group that the toggle button belongs to. + /// Use the GroupName property to specify a grouping of toggle buttons to + /// create a mutually exclusive set of controls. You can use the GroupName + /// property when only one selection is possible from a list of available + /// options. When this property is set, only one ToggleButton in the specified + /// group can be selected at a time. + /// + string GroupName { get; set; } + + /// + /// Gets or sets a value indicating whether SplitButton is checked + /// + bool? IsChecked { get; set; } + + /// + /// Gets a value that indicates whether the ToggleButton is fully loaded + /// + bool IsLoaded { get; } + } } \ No newline at end of file diff --git a/Fluent/Images/DefaultSmallIcon.png b/Fluent.Ribbon/Images/DefaultSmallIcon.png similarity index 100% rename from Fluent/Images/DefaultSmallIcon.png rename to Fluent.Ribbon/Images/DefaultSmallIcon.png diff --git a/Fluent/Internal/CommandHelper.cs b/Fluent.Ribbon/Internal/CommandHelper.cs similarity index 96% rename from Fluent/Internal/CommandHelper.cs rename to Fluent.Ribbon/Internal/CommandHelper.cs index a1b4aea8c..7278823cb 100644 --- a/Fluent/Internal/CommandHelper.cs +++ b/Fluent.Ribbon/Internal/CommandHelper.cs @@ -1,58 +1,58 @@ -namespace Fluent.Internal -{ - using System.Windows; - using System.Windows.Input; - - /// - /// Helper class for - /// - public static class CommandHelper - { - /// - /// Checks if can be executed. - /// This method is null safe. - /// - /// true if the command can be executed, otherwise false. - public static bool CanExecute(ICommand command, object commandParameter, IInputElement commandTarget) - { - if (command == null) - { - return false; - } - - var routedCommand = command as RoutedCommand; - - if (routedCommand != null) - { - return routedCommand.CanExecute(commandParameter, commandTarget); - } - - return command.CanExecute(commandParameter); ; - } - - /// - /// Executes . - /// This method is null safe. - /// - public static void Execute(ICommand command, object commandParameter, IInputElement commandTarget) - { - if (command == null) - { - return; - } - - var routedCommand = command as RoutedCommand; - if (routedCommand != null) - { - if (routedCommand.CanExecute(commandParameter, commandTarget)) - { - routedCommand.Execute(commandParameter, commandTarget); - } - } - else if (command.CanExecute(commandParameter)) - { - command.Execute(commandParameter); - } - } - } +namespace Fluent.Internal +{ + using System.Windows; + using System.Windows.Input; + + /// + /// Helper class for + /// + public static class CommandHelper + { + /// + /// Checks if can be executed. + /// This method is null safe. + /// + /// true if the command can be executed, otherwise false. + public static bool CanExecute(ICommand command, object commandParameter, IInputElement commandTarget) + { + if (command == null) + { + return false; + } + + var routedCommand = command as RoutedCommand; + + if (routedCommand != null) + { + return routedCommand.CanExecute(commandParameter, commandTarget); + } + + return command.CanExecute(commandParameter); ; + } + + /// + /// Executes . + /// This method is null safe. + /// + public static void Execute(ICommand command, object commandParameter, IInputElement commandTarget) + { + if (command == null) + { + return; + } + + var routedCommand = command as RoutedCommand; + if (routedCommand != null) + { + if (routedCommand.CanExecute(commandParameter, commandTarget)) + { + routedCommand.Execute(commandParameter, commandTarget); + } + } + else if (command.CanExecute(commandParameter)) + { + command.Execute(commandParameter); + } + } + } } \ No newline at end of file diff --git a/Fluent/Internal/DoubleUtil.cs b/Fluent.Ribbon/Internal/DoubleUtil.cs similarity index 97% rename from Fluent/Internal/DoubleUtil.cs rename to Fluent.Ribbon/Internal/DoubleUtil.cs index 87d03e438..5ec7d546a 100644 --- a/Fluent/Internal/DoubleUtil.cs +++ b/Fluent.Ribbon/Internal/DoubleUtil.cs @@ -1,39 +1,39 @@ -namespace Fluent.Internal -{ - using System; - - internal static class DoubleUtil - { - // Const values come from sdk\inc\crt\float.h - internal const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ - - /// - /// AreClose - Returns whether or not two doubles are "close". That is, whether or - /// not they are within epsilon of each other. Note that this epsilon is proportional - /// to the numbers themselves to that AreClose survives scalar multiplication. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. This is important enough to repeat: - /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be - /// used for optimizations *only*. - /// - /// - /// bool - the result of the AreClose comparision. - /// - /// The first double to compare. - /// The second double to compare. - public static bool AreClose(double value1, double value2) - { - // in case they are Infinities (then epsilon check does not work) - if (value1 == value2) - { - return true; - } - - // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON - var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; - var delta = value1 - value2; - return (-eps < delta) && (eps > delta); - } - } +namespace Fluent.Internal +{ + using System; + + internal static class DoubleUtil + { + // Const values come from sdk\inc\crt\float.h + internal const double DBL_EPSILON = 2.2204460492503131e-016; /* smallest such that 1.0+DBL_EPSILON != 1.0 */ + + /// + /// AreClose - Returns whether or not two doubles are "close". That is, whether or + /// not they are within epsilon of each other. Note that this epsilon is proportional + /// to the numbers themselves to that AreClose survives scalar multiplication. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. This is important enough to repeat: + /// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be + /// used for optimizations *only*. + /// + /// + /// bool - the result of the AreClose comparision. + /// + /// The first double to compare. + /// The second double to compare. + public static bool AreClose(double value1, double value2) + { + // in case they are Infinities (then epsilon check does not work) + if (value1 == value2) + { + return true; + } + + // This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON + var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON; + var delta = value1 - value2; + return (-eps < delta) && (eps > delta); + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Internal/FocusWrapper.cs b/Fluent.Ribbon/Internal/FocusWrapper.cs new file mode 100644 index 000000000..3538390e6 --- /dev/null +++ b/Fluent.Ribbon/Internal/FocusWrapper.cs @@ -0,0 +1,54 @@ +namespace Fluent.Internal +{ + using System; + using System.Windows; + using System.Windows.Input; + + internal class FocusWrapper + { + private readonly IInputElement inputElement; + private readonly IntPtr handle; + + private FocusWrapper(IInputElement inputElement) + { + this.inputElement = inputElement; + } + + private FocusWrapper(IntPtr handle) + { + this.handle = handle; + } + + public void Focus() + { + if (this.inputElement != null) + { + this.inputElement.Focus(); + return; + } + + if (this.handle != IntPtr.Zero) + { + NativeMethods.SetFocus(this.handle); + return; + } + } + + public static FocusWrapper GetWrapperForCurrentFocus() + { + if (Keyboard.FocusedElement != null) + { + return new FocusWrapper(Keyboard.FocusedElement); + } + + var handle = NativeMethods.GetFocus(); + + if (handle != IntPtr.Zero) + { + return new FocusWrapper(handle); + } + + return null; + } + } +} \ No newline at end of file diff --git a/Fluent/Internal/InvokeCommand.cs b/Fluent.Ribbon/Internal/InvokeCommand.cs similarity index 97% rename from Fluent/Internal/InvokeCommand.cs rename to Fluent.Ribbon/Internal/InvokeCommand.cs index 3a2c5cac3..2411456b4 100644 --- a/Fluent/Internal/InvokeCommand.cs +++ b/Fluent.Ribbon/Internal/InvokeCommand.cs @@ -1,66 +1,66 @@ -namespace Fluent.Internal -{ - using System.Windows; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Input; - using System.Windows.Interactivity; - - /// - /// This trigger action binds a command/command parameter for MVVM usage with - /// a Blend based trigger. This is used in place of the one in the Blend samples - - /// it has a problem in it as of the current (first) release. Once it is fixed, this - /// command can go away. - /// - [DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), "Click")] - [DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), "MouseLeftButtonDown")] - public class InvokeCommand : TriggerAction - { - /// - /// ICommand to execute - /// - public static readonly DependencyProperty CommandProperty = - DependencyProperty.Register("Command", typeof(ICommand), typeof(InvokeCommand), new PropertyMetadata(null)); - - /// - /// Command parameter to pass to command execution - /// - public static readonly DependencyProperty CommandParameterProperty = - DependencyProperty.Register("CommandParameter", typeof(object), typeof(InvokeCommand), new PropertyMetadata(null)); - - /// - /// Command to execute - /// - public ICommand Command - { - get { return (ICommand)this.GetValue(CommandProperty); } - set { this.SetValue(CommandProperty, value); } - } - - /// - /// Command parameter - /// - public object CommandParameter - { - get { return this.GetValue(CommandParameterProperty); } - set { this.SetValue(CommandParameterProperty, value); } - } - - /// - /// This is called to execute the command when the trigger conditions are satisfied. - /// - /// parameter (not used) - protected override void Invoke(object parameter) - { - var commandParameter = BindingOperations.IsDataBound(this, CommandParameterProperty) - ? this.CommandParameter - : parameter; - var command = this.Command; - - if ((command != null) && command.CanExecute(commandParameter)) - { - command.Execute(commandParameter); - } - } - } -} +namespace Fluent.Internal +{ + using System.Windows; + using System.Windows.Controls.Primitives; + using System.Windows.Data; + using System.Windows.Input; + using System.Windows.Interactivity; + + /// + /// This trigger action binds a command/command parameter for MVVM usage with + /// a Blend based trigger. This is used in place of the one in the Blend samples - + /// it has a problem in it as of the current (first) release. Once it is fixed, this + /// command can go away. + /// + [DefaultTrigger(typeof(ButtonBase), typeof(System.Windows.Interactivity.EventTrigger), "Click")] + [DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), "MouseLeftButtonDown")] + public class InvokeCommand : TriggerAction + { + /// + /// ICommand to execute + /// + public static readonly DependencyProperty CommandProperty = + DependencyProperty.Register("Command", typeof(ICommand), typeof(InvokeCommand), new PropertyMetadata(null)); + + /// + /// Command parameter to pass to command execution + /// + public static readonly DependencyProperty CommandParameterProperty = + DependencyProperty.Register("CommandParameter", typeof(object), typeof(InvokeCommand), new PropertyMetadata(null)); + + /// + /// Command to execute + /// + public ICommand Command + { + get { return (ICommand)this.GetValue(CommandProperty); } + set { this.SetValue(CommandProperty, value); } + } + + /// + /// Command parameter + /// + public object CommandParameter + { + get { return this.GetValue(CommandParameterProperty); } + set { this.SetValue(CommandParameterProperty, value); } + } + + /// + /// This is called to execute the command when the trigger conditions are satisfied. + /// + /// parameter (not used) + protected override void Invoke(object parameter) + { + var commandParameter = BindingOperations.IsDataBound(this, CommandParameterProperty) + ? this.CommandParameter + : parameter; + var command = this.Command; + + if ((command != null) && command.CanExecute(commandParameter)) + { + command.Execute(commandParameter); + } + } + } +} diff --git a/Fluent/Internal/ItemContainerGeneratorAction.cs b/Fluent.Ribbon/Internal/ItemContainerGeneratorAction.cs similarity index 97% rename from Fluent/Internal/ItemContainerGeneratorAction.cs rename to Fluent.Ribbon/Internal/ItemContainerGeneratorAction.cs index 8d73b7db5..04b2c93c7 100644 --- a/Fluent/Internal/ItemContainerGeneratorAction.cs +++ b/Fluent.Ribbon/Internal/ItemContainerGeneratorAction.cs @@ -1,66 +1,66 @@ -namespace Fluent.Internal -{ - using System; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - - /// - /// Helper class used to queue action for completion or items changes of - /// - internal class ItemContainerGeneratorAction - { - /// - /// Creates a new instance used to queue action for completion or items changes of - /// - /// The to be used. - /// The that should be invoked. - public ItemContainerGeneratorAction(ItemContainerGenerator generator, Action action) - { - this.Generator = generator; - this.Action = action; - } - - /// - /// Gets the to be used. - /// - public ItemContainerGenerator Generator { get; private set; } - - /// - /// Gets the that should be invoked. - /// - public Action Action { get; private set; } - - /// - /// Gets the current wait state. true in case was called and we are waiting for the to finish. - /// - public bool IsWaitingForGenerator { get; private set; } - - /// - /// Queues for invocation. - /// - public void QueueAction() - { - if (this.Generator.Status != GeneratorStatus.ContainersGenerated) - { - if (this.IsWaitingForGenerator) - { - return; - } - - this.IsWaitingForGenerator = true; - this.Generator.StatusChanged += this.HandleItemContainerGenerator_StatusChanged; - return; - } - - this.IsWaitingForGenerator = false; - this.Generator.StatusChanged -= this.HandleItemContainerGenerator_StatusChanged; - - this.Action(); - } - - private void HandleItemContainerGenerator_StatusChanged(object sender, EventArgs e) - { - this.QueueAction(); - } - } +namespace Fluent.Internal +{ + using System; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + + /// + /// Helper class used to queue action for completion or items changes of + /// + internal class ItemContainerGeneratorAction + { + /// + /// Creates a new instance used to queue action for completion or items changes of + /// + /// The to be used. + /// The that should be invoked. + public ItemContainerGeneratorAction(ItemContainerGenerator generator, Action action) + { + this.Generator = generator; + this.Action = action; + } + + /// + /// Gets the to be used. + /// + public ItemContainerGenerator Generator { get; private set; } + + /// + /// Gets the that should be invoked. + /// + public Action Action { get; private set; } + + /// + /// Gets the current wait state. true in case was called and we are waiting for the to finish. + /// + public bool IsWaitingForGenerator { get; private set; } + + /// + /// Queues for invocation. + /// + public void QueueAction() + { + if (this.Generator.Status != GeneratorStatus.ContainersGenerated) + { + if (this.IsWaitingForGenerator) + { + return; + } + + this.IsWaitingForGenerator = true; + this.Generator.StatusChanged += this.HandleItemContainerGenerator_StatusChanged; + return; + } + + this.IsWaitingForGenerator = false; + this.Generator.StatusChanged -= this.HandleItemContainerGenerator_StatusChanged; + + this.Action(); + } + + private void HandleItemContainerGenerator_StatusChanged(object sender, EventArgs e) + { + this.QueueAction(); + } + } } \ No newline at end of file diff --git a/Fluent/Internal/ItemsControlHelper.cs b/Fluent.Ribbon/Internal/ItemsControlHelper.cs similarity index 100% rename from Fluent/Internal/ItemsControlHelper.cs rename to Fluent.Ribbon/Internal/ItemsControlHelper.cs diff --git a/Fluent.Ribbon/Internal/KeyEventUtility.cs b/Fluent.Ribbon/Internal/KeyEventUtility.cs new file mode 100644 index 000000000..e84e023c5 --- /dev/null +++ b/Fluent.Ribbon/Internal/KeyEventUtility.cs @@ -0,0 +1,34 @@ +namespace Fluent.Internal +{ + using System.Windows.Input; + + internal static class KeyEventUtility + { + public static string GetStringFromKey(Key key) + { + var keyboardState = new byte[256]; + if (NativeMethods.GetKeyboardState(keyboardState) == false) + { + return null; + } + + var virtualKey = KeyInterop.VirtualKeyFromKey(key); + var scanCode = NativeMethods.MapVirtualKey((uint)virtualKey, NativeMethods.MapType.MAPVK_VK_TO_VSC); + var chars = new char[1]; + + var result = NativeMethods.ToUnicode((uint)virtualKey, scanCode, keyboardState, chars, chars.Length, 0); + switch (result) + { + case -1: + case 0: + return null; + + case 1: + return chars[0].ToString(); + + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/Fluent/Internal/NativeMethods.cs b/Fluent.Ribbon/Internal/NativeMethods.cs similarity index 51% rename from Fluent/Internal/NativeMethods.cs rename to Fluent.Ribbon/Internal/NativeMethods.cs index e8709fae4..b99c006f8 100644 --- a/Fluent/Internal/NativeMethods.cs +++ b/Fluent.Ribbon/Internal/NativeMethods.cs @@ -1,145 +1,310 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System; -using System.Runtime.InteropServices; - -namespace Fluent -{ - using Fluent.Metro.Native; - - internal static class NativeMethods - { - /// - /// Causes the dialog box to display all available colors in the set of basic colors. - /// - public const int CC_ANYCOLOR = 0x00000100; - - /// - /// The MonitorFromRect function retrieves a handle to the display monitor that - /// has the largest area of intersection with a specified rectangle. - /// - /// Pointer to a RECT structure that specifies the rectangle of interest in - /// virtual-screen coordinates - /// Determines the function's return value if the rectangle does not intersect - /// any display monitor - /// - /// If the rectangle intersects one or more display monitor rectangles, the return value - /// is an HMONITOR handle to the display monitor that has the largest area of intersection with the rectangle. - /// If the rectangle does not intersect a display monitor, the return value depends on the value of dwFlags. - /// - [DllImport("user32.dll")] - public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); - - /// - /// Loads an icon, cursor, animated cursor, or bitmap. - /// - /// Handle to the module of either a DLL or executable (.exe) that contains the image to be loaded - /// Specifies the image to load - /// Specifies the type of image to be loaded. - /// Specifies the width, in pixels, of the icon or cursor - /// Specifies the height, in pixels, of the icon or cursor - /// This parameter can be one or more of the following values. - /// If the function succeeds, the return value is the requested value.If the function fails, the return value is zero. To get extended error information, call GetLastError. - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr LoadImage(IntPtr hinst, IntPtr lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad); - - /// - /// Creates a Color dialog box that enables the user to select a color. - /// - /// A pointer to a CHOOSECOLOR structure that contains information used to initialize the dialog box. When ChooseColor returns, this structure contains information about the user's color selection. - /// If the user clicks the OK button of the dialog box, the return value is nonzero. The rgbResult member of the CHOOSECOLOR structure contains the RGB color value of the color selected by the user.If the user cancels or closes the Color dialog box or an error occurs, the return value is zero. - [DllImport("comdlg32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ChooseColor(CHOOSECOLOR lpcc); - - /// - /// Contains information the ChooseColor function uses to initialize the Color dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure. - /// - [StructLayout(LayoutKind.Sequential)] - public class CHOOSECOLOR - { - /// - /// The length, in bytes, of the structure. - /// - public int lStructSize = Marshal.SizeOf(typeof(CHOOSECOLOR)); - /// - /// A handle to the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner. - /// - public IntPtr hwndOwner; - /// - /// If the CC_ENABLETEMPLATEHANDLE flag is set in the Flags member, hInstance is a handle to a memory object containing a dialog box template. If the CC_ENABLETEMPLATE flag is set, hInstance is a handle to a module that contains a dialog box template named by the lpTemplateName member. If neither CC_ENABLETEMPLATEHANDLE nor CC_ENABLETEMPLATE is set, this member is ignored. - /// - public IntPtr hInstance = IntPtr.Zero; - /// - /// If the CC_RGBINIT flag is set, rgbResult specifies the color initially selected when the dialog box is created. If the specified color value is not among the available colors, the system selects the nearest solid color available. If rgbResult is zero or CC_RGBINIT is not set, the initially selected color is black. If the user clicks the OK button, rgbResult specifies the user's color selection. To create a COLORREF color value, use the RGB macro. - /// - public int rgbResult; - /// - /// A pointer to an array of 16 values that contain red, green, blue (RGB) values for the custom color boxes in the dialog box. If the user modifies these colors, the system updates the array with the new RGB values. To preserve new custom colors between calls to the ChooseColor function, you should allocate static memory for the array. To create a COLORREF color value, use the RGB macro. - /// - public IntPtr lpCustColors = IntPtr.Zero; - /// - /// A set of bit flags that you can use to initialize the Color dialog box. When the dialog box returns, it sets these flags to indicate the user's input. - /// - public int Flags; - /// - /// Application-defined data that the system passes to the hook procedure identified by the lpfnHook member. When the system sends the WM_INITDIALOG message to the hook procedure, the message's lParam parameter is a pointer to the CHOOSECOLOR structure specified when the dialog was created. The hook procedure can use this pointer to get the lCustData value. - /// - public IntPtr lCustData = IntPtr.Zero; - /// - /// A pointer to a CCHookProc hook procedure that can process messages intended for the dialog box. This member is ignored unless the CC_ENABLEHOOK flag is set in the Flags member. - /// - public IntPtr lpfnHook = IntPtr.Zero; - /// - /// The name of the dialog box template resource in the module identified by the hInstance member. This template is substituted for the standard dialog box template. For numbered dialog box resources, lpTemplateName can be a value returned by the MAKEINTRESOURCE macro. This member is ignored unless the CC_ENABLETEMPLATE flag is set in the Flags member. - /// - public IntPtr lpTemplateName = IntPtr.Zero; - } - - // Sets in first IsDwmEnabled call - private static bool idDwmDllNotFound; - - /// - /// Is DWM enabled - /// - /// Is DWM enabled - public static bool IsDwmEnabled() - { - if (idDwmDllNotFound) return false; - - if (Environment.OSVersion.Version.Major < 6) - { - idDwmDllNotFound = true; - return false; - } - - try - { - return UnsafeNativeMethods.DwmIsCompositionEnabled(); - } - catch (DllNotFoundException) - { - idDwmDllNotFound = true; - return false; - } - } - - /// - /// Sends a message to the message window and waits until the WndProc method has processed the message. - /// - /// Handle to destination window - /// Message - /// First message parameter - /// Second message parameter - /// - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); - } +using System; +using System.Runtime.InteropServices; + +namespace Fluent +{ + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Security; + using System.Text; + using Fluent.Metro.Native; + + internal static class NativeMethods + { + /// + /// Causes the dialog box to display all available colors in the set of basic colors. + /// + public const int CC_ANYCOLOR = 0x00000100; + + /// + /// The MonitorFromRect function retrieves a handle to the display monitor that + /// has the largest area of intersection with a specified rectangle. + /// + /// Pointer to a RECT structure that specifies the rectangle of interest in + /// virtual-screen coordinates + /// Determines the function's return value if the rectangle does not intersect + /// any display monitor + /// + /// If the rectangle intersects one or more display monitor rectangles, the return value + /// is an HMONITOR handle to the display monitor that has the largest area of intersection with the rectangle. + /// If the rectangle does not intersect a display monitor, the return value depends on the value of dwFlags. + /// + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); + + /// + /// Loads an icon, cursor, animated cursor, or bitmap. + /// + /// Handle to the module of either a DLL or executable (.exe) that contains the image to be loaded + /// Specifies the image to load + /// Specifies the type of image to be loaded. + /// Specifies the width, in pixels, of the icon or cursor + /// Specifies the height, in pixels, of the icon or cursor + /// This parameter can be one or more of the following values. + /// If the function succeeds, the return value is the requested value.If the function fails, the return value is zero. To get extended error information, call GetLastError. + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr LoadImage(IntPtr hinst, IntPtr lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad); + + /// + /// Creates a Color dialog box that enables the user to select a color. + /// + /// A pointer to a CHOOSECOLOR structure that contains information used to initialize the dialog box. When ChooseColor returns, this structure contains information about the user's color selection. + /// If the user clicks the OK button of the dialog box, the return value is nonzero. The rgbResult member of the CHOOSECOLOR structure contains the RGB color value of the color selected by the user.If the user cancels or closes the Color dialog box or an error occurs, the return value is zero. + [DllImport("comdlg32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ChooseColor(CHOOSECOLOR lpcc); + + /// + /// Contains information the ChooseColor function uses to initialize the Color dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure. + /// + [StructLayout(LayoutKind.Sequential)] + public class CHOOSECOLOR + { + /// + /// The length, in bytes, of the structure. + /// + public int lStructSize = Marshal.SizeOf(typeof(CHOOSECOLOR)); + /// + /// A handle to the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner. + /// + public IntPtr hwndOwner; + /// + /// If the CC_ENABLETEMPLATEHANDLE flag is set in the Flags member, hInstance is a handle to a memory object containing a dialog box template. If the CC_ENABLETEMPLATE flag is set, hInstance is a handle to a module that contains a dialog box template named by the lpTemplateName member. If neither CC_ENABLETEMPLATEHANDLE nor CC_ENABLETEMPLATE is set, this member is ignored. + /// + public IntPtr hInstance = IntPtr.Zero; + /// + /// If the CC_RGBINIT flag is set, rgbResult specifies the color initially selected when the dialog box is created. If the specified color value is not among the available colors, the system selects the nearest solid color available. If rgbResult is zero or CC_RGBINIT is not set, the initially selected color is black. If the user clicks the OK button, rgbResult specifies the user's color selection. To create a COLORREF color value, use the RGB macro. + /// + public int rgbResult; + /// + /// A pointer to an array of 16 values that contain red, green, blue (RGB) values for the custom color boxes in the dialog box. If the user modifies these colors, the system updates the array with the new RGB values. To preserve new custom colors between calls to the ChooseColor function, you should allocate static memory for the array. To create a COLORREF color value, use the RGB macro. + /// + public IntPtr lpCustColors = IntPtr.Zero; + /// + /// A set of bit flags that you can use to initialize the Color dialog box. When the dialog box returns, it sets these flags to indicate the user's input. + /// + public int Flags; + /// + /// Application-defined data that the system passes to the hook procedure identified by the lpfnHook member. When the system sends the WM_INITDIALOG message to the hook procedure, the message's lParam parameter is a pointer to the CHOOSECOLOR structure specified when the dialog was created. The hook procedure can use this pointer to get the lCustData value. + /// + public IntPtr lCustData = IntPtr.Zero; + /// + /// A pointer to a CCHookProc hook procedure that can process messages intended for the dialog box. This member is ignored unless the CC_ENABLEHOOK flag is set in the Flags member. + /// + public IntPtr lpfnHook = IntPtr.Zero; + /// + /// The name of the dialog box template resource in the module identified by the hInstance member. This template is substituted for the standard dialog box template. For numbered dialog box resources, lpTemplateName can be a value returned by the MAKEINTRESOURCE macro. This member is ignored unless the CC_ENABLETEMPLATE flag is set in the Flags member. + /// + public IntPtr lpTemplateName = IntPtr.Zero; + } + + // Sets in first IsDwmEnabled call + private static bool idDwmDllNotFound; + + /// + /// Is DWM enabled + /// + /// Is DWM enabled + public static bool IsDwmEnabled() + { + if (idDwmDllNotFound) return false; + + if (Environment.OSVersion.Version.Major < 6) + { + idDwmDllNotFound = true; + return false; + } + + try + { + return DwmIsCompositionEnabled(); + } + catch (DllNotFoundException) + { + idDwmDllNotFound = true; + return false; + } + } + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969518%28v=vs.85%29.aspx + [DllImport("dwmapi", PreserveSig = false, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DwmIsCompositionEnabled(); + + /// + /// Sends a message to the message window and waits until the WndProc method has processed the message. + /// + /// Handle to destination window + /// Message + /// First message parameter + /// Second message parameter + /// + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); + + /// http://msdn.microsoft.com/en-us/library/dd144901%28v=VS.85%29.aspx + [DllImport("user32", EntryPoint = "GetMonitorInfoW", ExactSpelling = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetMonitorInfo([In] IntPtr hMonitor, [Out] MONITORINFO lpmi); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633528(v=vs.85).aspx + [DllImport("user32", CharSet = CharSet.Auto, ExactSpelling = true)] + internal static extern bool IsWindow([In] [Optional] IntPtr hWnd); + + internal static IntPtr GetClassLong(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size == 4) + { + return new IntPtr(GetClassLong32(hWnd, nIndex)); + } + + return GetClassLong64(hWnd, nIndex); + } + + [DllImport("user32.dll", EntryPoint = "GetClassLong")] + private static extern uint GetClassLong32(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + private static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex); + + internal static void PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam) + { + if (!_PostMessage(hWnd, Msg, wParam, lParam)) + { + throw new Win32Exception(); + } + } + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx + [DllImport("user32", EntryPoint = "PostMessage", SetLastError = true)] + private static extern bool _PostMessage([In] [Optional] IntPtr hWnd, [In] uint Msg, [In] IntPtr wParam, [In] IntPtr lParam); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms647985(v=vs.85).aspx + [DllImport("user32")] + internal static extern IntPtr GetSystemMenu([In] IntPtr hWnd, [In] bool bRevert); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648003(v=vs.85).aspx + [DllImport("user32")] + internal static extern uint TrackPopupMenuEx([In] IntPtr hmenu, [In] uint fuFlags, [In] int x, [In] int y, [In] IntPtr hwnd, [In] [Optional] IntPtr lptpm); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx + [DllImport("kernel32", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryW", SetLastError = true, CallingConvention = CallingConvention.Winapi)] + internal static extern IntPtr LoadLibrary([In] [MarshalAs(UnmanagedType.LPWStr)] string lpFileName); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683152%28v=vs.85%29.aspx + [DllImport("kernel32", CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary([In] IntPtr hModule); + + /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms647486%28v=vs.85%29.aspx + [DllImport("user32", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadStringW", SetLastError = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int LoadString([In] [Optional] IntPtr hInstance, [In] uint uID, [Out] StringBuilder lpBuffer, [In] int nBufferMax); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern WS GetWindowLong(IntPtr hWnd, GWL nIndex); + + [DllImport("user32.dll")] + internal static extern int SetWindowLong(IntPtr hWnd, GWL nIndex, WS dwNewLong); + + [DllImport("user32.dll")] + internal static extern IntPtr GetFocus(); + + [DllImport("user32.dll")] + internal static extern IntPtr SetFocus(IntPtr hWnd); + + /// Add and remove a native WindowStyle from the HWND. + /// A HWND for a window. + /// The styles to be removed. These can be bitwise combined. + /// The styles to be added. These can be bitwise combined. + /// Whether the styles of the HWND were modified as a result of this call. + /// + /// Critical : Calls critical methods + /// + [SecurityCritical] + public static bool _ModifyStyle(this IntPtr _hwnd, WS removeStyle, WS addStyle) + { + var dwStyle = GetWindowLong(_hwnd, GWL.STYLE); + + var dwNewStyle = (dwStyle & ~removeStyle) | addStyle; + if (dwStyle == dwNewStyle) + { + return false; + } + + SetWindowLong(_hwnd, GWL.STYLE, dwNewStyle); + return true; + } + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + internal static extern int ToUnicode(uint virtualKey, uint scanCode, byte[] keyStates, [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, int charMaxCount, uint flags); + + [DllImport("user32.dll")] + internal static extern bool GetKeyboardState(byte[] lpKeyState); + + [DllImport("user32.dll")] + internal static extern uint MapVirtualKey(uint uCode, MapType uMapType); + + // ReSharper disable InconsistentNaming + internal enum MapType : uint + { + MAPVK_VK_TO_VSC = 0x0, + MAPVK_VSC_TO_VK = 0x1, + MAPVK_VK_TO_CHAR = 0x2, + MAPVK_VSC_TO_VK_EX = 0x3, + } + // ReSharper restore InconsistentNaming + + /// + /// GetWindowLong values, GWL_* + /// + internal enum GWL : int + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12) + } + + /// + /// WindowStyle values, WS_* + /// + [Flags] + internal enum WS : uint + { + OVERLAPPED = 0x00000000, + POPUP = 0x80000000, + CHILD = 0x40000000, + MINIMIZE = 0x20000000, + VISIBLE = 0x10000000, + DISABLED = 0x08000000, + CLIPSIBLINGS = 0x04000000, + CLIPCHILDREN = 0x02000000, + MAXIMIZE = 0x01000000, + BORDER = 0x00800000, + DLGFRAME = 0x00400000, + VSCROLL = 0x00200000, + HSCROLL = 0x00100000, + SYSMENU = 0x00080000, + THICKFRAME = 0x00040000, + GROUP = 0x00020000, + TABSTOP = 0x00010000, + + MINIMIZEBOX = 0x00020000, + MAXIMIZEBOX = 0x00010000, + + CAPTION = BORDER | DLGFRAME, + TILED = OVERLAPPED, + ICONIC = MINIMIZE, + SIZEBOX = THICKFRAME, + TILEDWINDOW = OVERLAPPEDWINDOW, + + OVERLAPPEDWINDOW = OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX, + POPUPWINDOW = POPUP | BORDER | SYSMENU, + CHILDWINDOW = CHILD, + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Internal/UIHelper.cs b/Fluent.Ribbon/Internal/UIHelper.cs new file mode 100644 index 000000000..cad9cbe28 --- /dev/null +++ b/Fluent.Ribbon/Internal/UIHelper.cs @@ -0,0 +1,112 @@ +namespace Fluent.Internal +{ + using System; + using System.Collections.Generic; + using System.Windows; + using System.Windows.Media; + + /// + /// Class with helper functions for UI related stuff + /// + internal static class UIHelper + { + /// + /// Tries to find immediate visual child of type which matches + /// + /// + /// The visual child of type that matches . + /// Returns null if no child matches. + /// + public static T FindImmediateVisualChild(DependencyObject parent, Predicate predicate) + where T : DependencyObject + { + foreach (var child in GetVisualChildren(parent)) + { + var obj = child as T; + + if (obj != null + && predicate(obj)) + { + return obj; + } + } + + return null; + } + + /// + /// Gets the first visual child of type TChildItem by walking down the visual tree. + /// + /// The type of visual child to find. + /// The parent element whose visual tree shall be walked down. + /// The first element of type TChildItem found in the visual tree is returned. If none is found, null is returned. + public static TChildItem FindVisualChild(DependencyObject parent) where TChildItem : DependencyObject + { + foreach (var child in GetVisualChildren(parent)) + { + var item = child as TChildItem; + + if (item != null) + { + return item; + } + + var childOfChild = FindVisualChild(child); + if (childOfChild != null) + { + return childOfChild; + } + } + return null; + } + + /// + /// Gets all visual children of . + /// + /// + public static IEnumerable GetVisualChildren(DependencyObject parent) + { + var visualChildrenCount = VisualTreeHelper.GetChildrenCount(parent); + + for (var i = 0; i < visualChildrenCount; i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + + if (child != null) + { + yield return child; + } + } + } + + /// + /// Finds the parent control of type . + /// First looks at the visual tree and then at the logical tree to find the parent. + /// + /// The found visual/logical parent or null. + public static T GetParent(DependencyObject element) + where T : DependencyObject + { + var item = element; + + while (item != null + && item is T == false) + { + item = VisualTreeHelper.GetParent(item); + } + + if (item == null) + { + item = element; + + while (item != null && + item is T == false) + { + item = LogicalTreeHelper.GetParent(item); + } + } + + return (T)item; + } + } +} \ No newline at end of file diff --git a/Fluent/Metro/Behaviours/StylizedBehaviors.cs b/Fluent.Ribbon/Metro/Behaviours/StylizedBehaviors.cs similarity index 97% rename from Fluent/Metro/Behaviours/StylizedBehaviors.cs rename to Fluent.Ribbon/Metro/Behaviours/StylizedBehaviors.cs index 7f57c824a..18e450c38 100644 --- a/Fluent/Metro/Behaviours/StylizedBehaviors.cs +++ b/Fluent.Ribbon/Metro/Behaviours/StylizedBehaviors.cs @@ -1,127 +1,127 @@ -using System.Windows; -using System.Windows.Interactivity; - -namespace Fluent.Metro.Behaviours -{ - /// - /// Enables the use of behaviors in styles - /// - public class StylizedBehaviors - { - private static readonly DependencyProperty OriginalBehaviorProperty = DependencyProperty.RegisterAttached(@"OriginalBehaviorInternal", typeof(Behavior), typeof(StylizedBehaviors), new UIPropertyMetadata(null)); - - /// - /// Using a DependencyProperty as the backing store for Behaviors. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached( - @"Behaviors", - typeof(StylizedBehaviorCollection), - typeof(StylizedBehaviors), - new FrameworkPropertyMetadata(null, OnPropertyChanged)); - - /// - /// Gets Behaviors for element - /// - public static StylizedBehaviorCollection GetBehaviors(DependencyObject uie) - { - return (StylizedBehaviorCollection)uie.GetValue(BehaviorsProperty); - } - - /// - /// Sets Behaviors for element - /// - public static void SetBehaviors(DependencyObject uie, StylizedBehaviorCollection value) - { - uie.SetValue(BehaviorsProperty, value); - } - - private static Behavior GetOriginalBehavior(DependencyObject obj) - { - return obj.GetValue(OriginalBehaviorProperty) as Behavior; - } - - private static int GetIndexOf(BehaviorCollection itemBehaviors, Behavior behavior) - { - int index = -1; - - Behavior orignalBehavior = GetOriginalBehavior(behavior); - - for (int i = 0; i < itemBehaviors.Count; i++) - { - Behavior currentBehavior = itemBehaviors[i]; - - if (currentBehavior == behavior - || currentBehavior == orignalBehavior) - { - index = i; - break; - } - - Behavior currentOrignalBehavior = GetOriginalBehavior(currentBehavior); - - if (currentOrignalBehavior == behavior - || currentOrignalBehavior == orignalBehavior) - { - index = i; - break; - } - } - - return index; - } - - private static void OnPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e) - { - var uie = dpo as UIElement; - - if (uie == null) - { - return; - } - - BehaviorCollection itemBehaviors = Interaction.GetBehaviors(uie); - - var newBehaviors = e.NewValue as StylizedBehaviorCollection; - var oldBehaviors = e.OldValue as StylizedBehaviorCollection; - - if (newBehaviors == oldBehaviors) - { - return; - } - - if (oldBehaviors != null) - { - foreach (var behavior in oldBehaviors) - { - int index = GetIndexOf(itemBehaviors, behavior); - - if (index >= 0) - { - itemBehaviors.RemoveAt(index); - } - } - } - - if (newBehaviors != null) - { - foreach (var behavior in newBehaviors) - { - int index = GetIndexOf(itemBehaviors, behavior); - - if (index < 0) - { - var clone = (Behavior)behavior.Clone(); - SetOriginalBehavior(clone, behavior); - itemBehaviors.Add(clone); - } - } - } - } - - private static void SetOriginalBehavior(DependencyObject obj, Behavior value) - { - obj.SetValue(OriginalBehaviorProperty, value); - } - } +using System.Windows; +using System.Windows.Interactivity; + +namespace Fluent.Metro.Behaviours +{ + /// + /// Enables the use of behaviors in styles + /// + public class StylizedBehaviors + { + private static readonly DependencyProperty OriginalBehaviorProperty = DependencyProperty.RegisterAttached(@"OriginalBehaviorInternal", typeof(Behavior), typeof(StylizedBehaviors), new UIPropertyMetadata(null)); + + /// + /// Using a DependencyProperty as the backing store for Behaviors. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached( + @"Behaviors", + typeof(StylizedBehaviorCollection), + typeof(StylizedBehaviors), + new FrameworkPropertyMetadata(null, OnPropertyChanged)); + + /// + /// Gets Behaviors for element + /// + public static StylizedBehaviorCollection GetBehaviors(DependencyObject uie) + { + return (StylizedBehaviorCollection)uie.GetValue(BehaviorsProperty); + } + + /// + /// Sets Behaviors for element + /// + public static void SetBehaviors(DependencyObject uie, StylizedBehaviorCollection value) + { + uie.SetValue(BehaviorsProperty, value); + } + + private static Behavior GetOriginalBehavior(DependencyObject obj) + { + return obj.GetValue(OriginalBehaviorProperty) as Behavior; + } + + private static int GetIndexOf(BehaviorCollection itemBehaviors, Behavior behavior) + { + int index = -1; + + Behavior orignalBehavior = GetOriginalBehavior(behavior); + + for (int i = 0; i < itemBehaviors.Count; i++) + { + Behavior currentBehavior = itemBehaviors[i]; + + if (currentBehavior == behavior + || currentBehavior == orignalBehavior) + { + index = i; + break; + } + + Behavior currentOrignalBehavior = GetOriginalBehavior(currentBehavior); + + if (currentOrignalBehavior == behavior + || currentOrignalBehavior == orignalBehavior) + { + index = i; + break; + } + } + + return index; + } + + private static void OnPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e) + { + var uie = dpo as UIElement; + + if (uie == null) + { + return; + } + + BehaviorCollection itemBehaviors = Interaction.GetBehaviors(uie); + + var newBehaviors = e.NewValue as StylizedBehaviorCollection; + var oldBehaviors = e.OldValue as StylizedBehaviorCollection; + + if (newBehaviors == oldBehaviors) + { + return; + } + + if (oldBehaviors != null) + { + foreach (var behavior in oldBehaviors) + { + int index = GetIndexOf(itemBehaviors, behavior); + + if (index >= 0) + { + itemBehaviors.RemoveAt(index); + } + } + } + + if (newBehaviors != null) + { + foreach (var behavior in newBehaviors) + { + int index = GetIndexOf(itemBehaviors, behavior); + + if (index < 0) + { + var clone = (Behavior)behavior.Clone(); + SetOriginalBehavior(clone, behavior); + itemBehaviors.Add(clone); + } + } + } + } + + private static void SetOriginalBehavior(DependencyObject obj, Behavior value) + { + obj.SetValue(OriginalBehaviorProperty, value); + } + } } \ No newline at end of file diff --git a/Fluent/Metro/Behaviours/StylizedBehaviorsCollection.cs b/Fluent.Ribbon/Metro/Behaviours/StylizedBehaviorsCollection.cs similarity index 96% rename from Fluent/Metro/Behaviours/StylizedBehaviorsCollection.cs rename to Fluent.Ribbon/Metro/Behaviours/StylizedBehaviorsCollection.cs index 7a5fce9a7..65dffba6c 100644 --- a/Fluent/Metro/Behaviours/StylizedBehaviorsCollection.cs +++ b/Fluent.Ribbon/Metro/Behaviours/StylizedBehaviorsCollection.cs @@ -1,22 +1,22 @@ -namespace Fluent.Metro.Behaviours -{ - using System.Windows; - using System.Windows.Interactivity; - - /// - /// Just a for - /// - public class StylizedBehaviorCollection : FreezableCollection - { - /// - /// Creates a new instance of the . - /// - /// - /// The new instance. - /// - protected override Freezable CreateInstanceCore() - { - return new StylizedBehaviorCollection(); - } - } +namespace Fluent.Metro.Behaviours +{ + using System.Windows; + using System.Windows.Interactivity; + + /// + /// Just a for + /// + public class StylizedBehaviorCollection : FreezableCollection + { + /// + /// Creates a new instance of the . + /// + /// + /// The new instance. + /// + protected override Freezable CreateInstanceCore() + { + return new StylizedBehaviorCollection(); + } + } } \ No newline at end of file diff --git a/Fluent/Metro/Controls/WindowCommands.cs b/Fluent.Ribbon/Metro/Controls/WindowCommands.cs similarity index 94% rename from Fluent/Metro/Controls/WindowCommands.cs rename to Fluent.Ribbon/Metro/Controls/WindowCommands.cs index f91352be5..700ff27ba 100644 --- a/Fluent/Metro/Controls/WindowCommands.cs +++ b/Fluent.Ribbon/Metro/Controls/WindowCommands.cs @@ -1,276 +1,276 @@ -namespace Fluent -{ - using System; - using System.Text; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Media; - using Fluent.Metro.Native; - - /// - /// Contains commands for - /// - [TemplatePart(Name = "PART_Max", Type = typeof(Button))] - [TemplatePart(Name = "PART_Close", Type = typeof(Button))] - [TemplatePart(Name = "PART_Min", Type = typeof(Button))] - public class WindowCommands : ItemsControl, IDisposable - { - private static string minimize; - private static string maximize; - private static string closeText; - private static string restore; - private System.Windows.Controls.Button min; - private System.Windows.Controls.Button max; - private System.Windows.Controls.Button close; - private IntPtr user32 = IntPtr.Zero; - private bool disposed; - - static WindowCommands() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommands), new FrameworkPropertyMetadata(typeof(WindowCommands))); - } - - /// - /// Finalizer - /// - ~WindowCommands() - { - this.Dispose(false); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - this.Dispose(true); - - GC.SuppressFinalize(this); - } - - /// - /// Dispose(bool disposing) executes in two distinct scenarios. - /// If disposing equals true, the method has been called directly - /// or indirectly by a user's code. Managed and unmanaged resources - /// can be disposed. - /// If disposing equals false, the method has been called by the - /// runtime from inside the finalizer and you should not reference - /// other objects. Only unmanaged resources can be disposed. - /// - protected virtual void Dispose(bool disposing) - { - // Check to see if Dispose has already been called. - if (this.disposed) - { - return; - } - - // If disposing equals true, dispose all managed - // and unmanaged resources. - if (disposing) - { - // Dispose managed resources. - } - - // Call the appropriate methods to clean up - // unmanaged resources here. - // If disposing is false, - // only the following code is executed. - if (this.user32 != IntPtr.Zero) - { - UnsafeNativeMethods.FreeLibrary(this.user32); - this.user32 = IntPtr.Zero; - } - - // Note disposing has been done. - this.disposed = true; - } - - /// - /// Retrieves the translated string for Minimize - /// - public string Minimize - { - get - { - if (string.IsNullOrEmpty(minimize)) - minimize = this.GetCaption(900); - return minimize; - } - } - - /// - /// Retrieves the translated string for Maximize - /// - public string Maximize - { - get - { - if (string.IsNullOrEmpty(maximize)) - maximize = this.GetCaption(901); - return maximize; - } - } - - /// - /// Retrieves the translated string for Close - /// - public string Close - { - get - { - if (string.IsNullOrEmpty(closeText)) - closeText = this.GetCaption(905); - return closeText; - } - } - - /// - /// Retrieves the translated string for Restore - /// - public string Restore - { - get - { - if (string.IsNullOrEmpty(restore)) - { - restore = this.GetCaption(903); - } - - return restore; - } - } - - /// - /// Gets or sets the button brush - /// - public Brush ButtonBrush - { - get { return (Brush)this.GetValue(ButtonBrushProperty); } - set { this.SetValue(ButtonBrushProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ButtonBrush. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ButtonBrushProperty = DependencyProperty.Register("ButtonBrush", typeof(Brush), typeof(WindowCommands), new PropertyMetadata(Brushes.Black)); - - private string GetCaption(int id) - { - if (this.user32 == IntPtr.Zero) - { - this.user32 = UnsafeNativeMethods.LoadLibrary(Environment.SystemDirectory + "\\User32.dll"); - } - - var sb = new StringBuilder(256); - UnsafeNativeMethods.LoadString(this.user32, (uint)id, sb, sb.Capacity); - return sb.ToString().Replace("&", ""); - } - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call . - /// - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - this.close = this.GetTemplateChild("PART_Close") as System.Windows.Controls.Button;//Template.FindName("PART_Close", this) as Button; - if (this.close != null) - this.close.Click += this.CloseClick; - - this.max = this.Template.FindName("PART_Max", this) as System.Windows.Controls.Button; - if (this.max != null) - this.max.Click += this.MaximiseClick; - - this.min = this.Template.FindName("PART_Min", this) as System.Windows.Controls.Button; - if (this.min != null) - this.min.Click += this.MinimiseClick; - - this.RefreshMaximizeIconState(); - } - - private void MinimiseClick(object sender, RoutedEventArgs e) - { - var parentWindow = this.GetParentWindow(); - if (parentWindow != null) - parentWindow.WindowState = WindowState.Minimized; - } - - private void MaximiseClick(object sender, RoutedEventArgs e) - { - var parentWindow = this.GetParentWindow(); - if (parentWindow == null) - return; - - parentWindow.WindowState = parentWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; - this.RefreshMaximizeIconState(parentWindow); - } - - /// - /// Upates the visual state of the maximize icon - /// - public void RefreshMaximizeIconState() - { - this.RefreshMaximizeIconState(this.GetParentWindow()); - } - - private void RefreshMaximizeIconState(Window parentWindow) - { - if (parentWindow == null) - return; - - if (parentWindow.WindowState == WindowState.Normal) - { - var maxpath = (UIElement)this.max.FindName("PART_MaximizeButtonContent"); - if (maxpath != null) - { - maxpath.Visibility = Visibility.Visible; - } - - var restorepath = (UIElement)this.max.FindName("PART_RestoreButtonContent"); - if (restorepath != null) - { - restorepath.Visibility = Visibility.Collapsed; - } - - this.max.ToolTip = this.Maximize; - } - else - { - var restorepath = (UIElement)this.max.FindName("PART_RestoreButtonContent"); - if (restorepath != null) - { - restorepath.Visibility = Visibility.Visible; - } - - var maxpath = (UIElement)this.max.FindName("PART_MaximizeButtonContent"); - if (maxpath != null) - { - maxpath.Visibility = Visibility.Collapsed; - } - this.max.ToolTip = this.Restore; - } - } - - private void CloseClick(object sender, RoutedEventArgs e) - { - var parentWindow = this.GetParentWindow(); - if (parentWindow != null) - { - parentWindow.Close(); - } - } - - private Window GetParentWindow() - { - var parent = VisualTreeHelper.GetParent(this); - - while (parent != null && !(parent is Window)) - { - parent = VisualTreeHelper.GetParent(parent); - } - - var parentWindow = parent as Window; - return parentWindow; - } - } +namespace Fluent +{ + using System; + using System.Text; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Media; + using Fluent.Metro.Native; + + /// + /// Contains commands for + /// + [TemplatePart(Name = "PART_Max", Type = typeof(Button))] + [TemplatePart(Name = "PART_Close", Type = typeof(Button))] + [TemplatePart(Name = "PART_Min", Type = typeof(Button))] + public class WindowCommands : ItemsControl, IDisposable + { + private static string minimize; + private static string maximize; + private static string closeText; + private static string restore; + private System.Windows.Controls.Button min; + private System.Windows.Controls.Button max; + private System.Windows.Controls.Button close; + private IntPtr user32 = IntPtr.Zero; + private bool disposed; + + static WindowCommands() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommands), new FrameworkPropertyMetadata(typeof(WindowCommands))); + } + + /// + /// Finalizer + /// + ~WindowCommands() + { + this.Dispose(false); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + this.Dispose(true); + + GC.SuppressFinalize(this); + } + + /// + /// Dispose(bool disposing) executes in two distinct scenarios. + /// If disposing equals true, the method has been called directly + /// or indirectly by a user's code. Managed and unmanaged resources + /// can be disposed. + /// If disposing equals false, the method has been called by the + /// runtime from inside the finalizer and you should not reference + /// other objects. Only unmanaged resources can be disposed. + /// + protected virtual void Dispose(bool disposing) + { + // Check to see if Dispose has already been called. + if (this.disposed) + { + return; + } + + // If disposing equals true, dispose all managed + // and unmanaged resources. + if (disposing) + { + // Dispose managed resources. + } + + // Call the appropriate methods to clean up + // unmanaged resources here. + // If disposing is false, + // only the following code is executed. + if (this.user32 != IntPtr.Zero) + { + NativeMethods.FreeLibrary(this.user32); + this.user32 = IntPtr.Zero; + } + + // Note disposing has been done. + this.disposed = true; + } + + /// + /// Retrieves the translated string for Minimize + /// + public string Minimize + { + get + { + if (string.IsNullOrEmpty(minimize)) + minimize = this.GetCaption(900); + return minimize; + } + } + + /// + /// Retrieves the translated string for Maximize + /// + public string Maximize + { + get + { + if (string.IsNullOrEmpty(maximize)) + maximize = this.GetCaption(901); + return maximize; + } + } + + /// + /// Retrieves the translated string for Close + /// + public string Close + { + get + { + if (string.IsNullOrEmpty(closeText)) + closeText = this.GetCaption(905); + return closeText; + } + } + + /// + /// Retrieves the translated string for Restore + /// + public string Restore + { + get + { + if (string.IsNullOrEmpty(restore)) + { + restore = this.GetCaption(903); + } + + return restore; + } + } + + /// + /// Gets or sets the button brush + /// + public Brush ButtonBrush + { + get { return (Brush)this.GetValue(ButtonBrushProperty); } + set { this.SetValue(ButtonBrushProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for ButtonBrush. This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty ButtonBrushProperty = DependencyProperty.Register("ButtonBrush", typeof(Brush), typeof(WindowCommands), new PropertyMetadata(Brushes.Black)); + + private string GetCaption(int id) + { + if (this.user32 == IntPtr.Zero) + { + this.user32 = NativeMethods.LoadLibrary(Environment.SystemDirectory + "\\User32.dll"); + } + + var sb = new StringBuilder(256); + NativeMethods.LoadString(this.user32, (uint)id, sb, sb.Capacity); + return sb.ToString().Replace("&", ""); + } + + /// + /// When overridden in a derived class, is invoked whenever application code or internal processes call . + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + this.close = this.GetTemplateChild("PART_Close") as System.Windows.Controls.Button;//Template.FindName("PART_Close", this) as Button; + if (this.close != null) + this.close.Click += this.CloseClick; + + this.max = this.Template.FindName("PART_Max", this) as System.Windows.Controls.Button; + if (this.max != null) + this.max.Click += this.MaximiseClick; + + this.min = this.Template.FindName("PART_Min", this) as System.Windows.Controls.Button; + if (this.min != null) + this.min.Click += this.MinimiseClick; + + this.RefreshMaximizeIconState(); + } + + private void MinimiseClick(object sender, RoutedEventArgs e) + { + var parentWindow = this.GetParentWindow(); + if (parentWindow != null) + parentWindow.WindowState = WindowState.Minimized; + } + + private void MaximiseClick(object sender, RoutedEventArgs e) + { + var parentWindow = this.GetParentWindow(); + if (parentWindow == null) + return; + + parentWindow.WindowState = parentWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; + this.RefreshMaximizeIconState(parentWindow); + } + + /// + /// Upates the visual state of the maximize icon + /// + public void RefreshMaximizeIconState() + { + this.RefreshMaximizeIconState(this.GetParentWindow()); + } + + private void RefreshMaximizeIconState(Window parentWindow) + { + if (parentWindow == null) + return; + + if (parentWindow.WindowState == WindowState.Normal) + { + var maxpath = (UIElement)this.max.FindName("PART_MaximizeButtonContent"); + if (maxpath != null) + { + maxpath.Visibility = Visibility.Visible; + } + + var restorepath = (UIElement)this.max.FindName("PART_RestoreButtonContent"); + if (restorepath != null) + { + restorepath.Visibility = Visibility.Collapsed; + } + + this.max.ToolTip = this.Maximize; + } + else + { + var restorepath = (UIElement)this.max.FindName("PART_RestoreButtonContent"); + if (restorepath != null) + { + restorepath.Visibility = Visibility.Visible; + } + + var maxpath = (UIElement)this.max.FindName("PART_MaximizeButtonContent"); + if (maxpath != null) + { + maxpath.Visibility = Visibility.Collapsed; + } + this.max.ToolTip = this.Restore; + } + } + + private void CloseClick(object sender, RoutedEventArgs e) + { + var parentWindow = this.GetParentWindow(); + if (parentWindow != null) + { + parentWindow.Close(); + } + } + + private Window GetParentWindow() + { + var parent = VisualTreeHelper.GetParent(this); + + while (parent != null && !(parent is Window)) + { + parent = VisualTreeHelper.GetParent(parent); + } + + var parentWindow = parent as Window; + return parentWindow; + } + } } \ No newline at end of file diff --git a/Fluent/Metro/MetroColors.cs b/Fluent.Ribbon/Metro/MetroColors.cs similarity index 97% rename from Fluent/Metro/MetroColors.cs rename to Fluent.Ribbon/Metro/MetroColors.cs index f10161734..f49c3cad6 100644 --- a/Fluent/Metro/MetroColors.cs +++ b/Fluent.Ribbon/Metro/MetroColors.cs @@ -1,15 +1,15 @@ -namespace Fluent -{ - using System.Windows; - - /// - /// Collection of some for the Metro/Office 2013 theme - /// - public static class MetroColors - { - /// - /// Gets the theme color - /// - public static readonly ComponentResourceKey ThemeColorKey = new ComponentResourceKey(typeof(MetroColors), "ThemeColor"); - } +namespace Fluent +{ + using System.Windows; + + /// + /// Collection of some for the Metro/Office 2013 theme + /// + public static class MetroColors + { + /// + /// Gets the theme color + /// + public static readonly ComponentResourceKey ThemeColorKey = new ComponentResourceKey(typeof(MetroColors), "ThemeColor"); + } } \ No newline at end of file diff --git a/Fluent/Metro/Native/Constants.cs b/Fluent.Ribbon/Metro/Native/Constants.cs similarity index 93% rename from Fluent/Metro/Native/Constants.cs rename to Fluent.Ribbon/Metro/Native/Constants.cs index 69f90b2f8..da7f9791a 100644 --- a/Fluent/Metro/Native/Constants.cs +++ b/Fluent.Ribbon/Metro/Native/Constants.cs @@ -1,46 +1,47 @@ -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 -#pragma warning disable 3003 - internal static class Constants - { - public const int MONITOR_DEFAULTTONEAREST = 0x00000002; - - public const int WM_NCCALCSIZE = 0x83; - public const int WM_NCPAINT = 0x85; - public const int WM_NCACTIVATE = 0x86; - public const int WM_GETMINMAXINFO = 0x24; - public const int WM_STYLECHANGED = 0x7d; - public const int WM_CREATE = 0x0001; - public const int WM_NCHITTEST = 0x84; - public const int WM_SIZE = 0x0005; - - public const long WS_MAXIMIZE = 0x01000000; - - public const int GCLP_HBRBACKGROUND = -0x0A; - - public const int HTLEFT = 0x0A; - public const int HTRIGHT = 0x0B; - public const int HTTOP = 0x0C; - public const int HTTOPLEFT = 0x0D; - public const int HTTOPRIGHT = 0x0E; - public const int HTBOTTOM = 0x0F; - public const int HTBOTTOMLEFT = 0x10; - public const int HTBOTTOMRIGHT = 0x11; - public const uint TPM_RETURNCMD = 0x0100; - public const uint TPM_LEFTBUTTON = 0x0; - public const int SW_SHOWNORMAL = 1; - public const int SW_SHOWMINIMIZED = 2; - public const uint SYSCOMMAND = 0x0112; - public const int WM_INITMENU = 0x116; - - public const int SC_MAXIMIZE = 0xF030; - public const int SC_SIZE = 0xF000; - public const int SC_MINIMIZE = 0xF020; - public const int SC_RESTORE = 0xF120; - public const int SC_MOVE = 0xF010; - public const int MF_GRAYED = 0x00000001; - public const int MF_BYCOMMAND = 0x00000000; - public const int MF_ENABLED = 0x00000000; - } +namespace Fluent.Metro.Native +{ +#pragma warning disable 1591 +#pragma warning disable 3003 + internal static class Constants + { + public const int MONITOR_DEFAULTTONEAREST = 0x00000002; + + public const int WM_ACTIVATE = 0x0006; + public const int WM_NCCALCSIZE = 0x83; + public const int WM_NCPAINT = 0x85; + public const int WM_NCACTIVATE = 0x86; + public const int WM_GETMINMAXINFO = 0x24; + public const int WM_STYLECHANGED = 0x7d; + public const int WM_CREATE = 0x0001; + public const int WM_NCHITTEST = 0x84; + public const int WM_SIZE = 0x0005; + + public const long WS_MAXIMIZE = 0x01000000; + + public const int GCLP_HBRBACKGROUND = -0x0A; + + public const int HTLEFT = 0x0A; + public const int HTRIGHT = 0x0B; + public const int HTTOP = 0x0C; + public const int HTTOPLEFT = 0x0D; + public const int HTTOPRIGHT = 0x0E; + public const int HTBOTTOM = 0x0F; + public const int HTBOTTOMLEFT = 0x10; + public const int HTBOTTOMRIGHT = 0x11; + public const uint TPM_RETURNCMD = 0x0100; + public const uint TPM_LEFTBUTTON = 0x0; + public const int SW_SHOWNORMAL = 1; + public const int SW_SHOWMINIMIZED = 2; + public const uint SYSCOMMAND = 0x0112; + public const int WM_INITMENU = 0x116; + + public const int SC_MAXIMIZE = 0xF030; + public const int SC_SIZE = 0xF000; + public const int SC_MINIMIZE = 0xF020; + public const int SC_RESTORE = 0xF120; + public const int SC_MOVE = 0xF010; + public const int MF_GRAYED = 0x00000001; + public const int MF_BYCOMMAND = 0x00000000; + public const int MF_ENABLED = 0x00000000; + } } \ No newline at end of file diff --git a/Fluent/Metro/Native/MONITORINFO.cs b/Fluent.Ribbon/Metro/Native/MONITORINFO.cs similarity index 96% rename from Fluent/Metro/Native/MONITORINFO.cs rename to Fluent.Ribbon/Metro/Native/MONITORINFO.cs index 127be9999..33208eae1 100644 --- a/Fluent/Metro/Native/MONITORINFO.cs +++ b/Fluent.Ribbon/Metro/Native/MONITORINFO.cs @@ -1,21 +1,21 @@ -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ - #pragma warning disable 1591 - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - internal class MONITORINFO - { - public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); - public RECT rcMonitor = new RECT(); - public RECT rcWork = new RECT(); - public int dwFlags = 0; - - public enum MonitorOptions - { - MONITOR_DEFAULTTONULL = 0x00000000, - MONITOR_DEFAULTTOPRIMARY = 0x00000001, - MONITOR_DEFAULTTONEAREST = 0x00000002 - } - } +using System.Runtime.InteropServices; + +namespace Fluent.Metro.Native +{ + #pragma warning disable 1591 + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + public RECT rcMonitor = new RECT(); + public RECT rcWork = new RECT(); + public int dwFlags = 0; + + public enum MonitorOptions + { + MONITOR_DEFAULTTONULL = 0x00000000, + MONITOR_DEFAULTTOPRIMARY = 0x00000001, + MONITOR_DEFAULTTONEAREST = 0x00000002 + } + } } \ No newline at end of file diff --git a/Fluent/Metro/Native/RECT.cs b/Fluent.Ribbon/Metro/Native/RECT.cs similarity index 96% rename from Fluent/Metro/Native/RECT.cs rename to Fluent.Ribbon/Metro/Native/RECT.cs index fb1f1191b..c07b67193 100644 --- a/Fluent/Metro/Native/RECT.cs +++ b/Fluent.Ribbon/Metro/Native/RECT.cs @@ -1,91 +1,91 @@ -using System; -using System.Runtime.InteropServices; -using System.Windows; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [Serializable] - [StructLayout(LayoutKind.Sequential, Pack = 0)] - internal struct RECT - { - public int left; - public int top; - public int right; - public int bottom; - - public static readonly RECT Empty; - - public int Width - { - get { return Math.Abs(this.right - this.left); } // Abs needed for BIDI OS - } - - public int Height - { - get { return this.bottom - this.top; } - } - - public RECT(int left, int top, int right, int bottom) - { - this.left = left; - this.top = top; - this.right = right; - this.bottom = bottom; - } - - public RECT(RECT rcSrc) - { - this.left = rcSrc.left; - this.top = rcSrc.top; - this.right = rcSrc.right; - this.bottom = rcSrc.bottom; - } - - public bool IsEmpty - { - get - { - // BUGBUG : On Bidi OS (hebrew arabic) left > right - return this.left >= this.right || this.top >= this.bottom; - } - } - - public override string ToString() - { - if (this == Empty) - { - return "RECT {Empty}"; - } - - return string.Format("RECT {{ left: {0} / top: {1} / right: {2} / bottom: {3} }}", this.left, this.top, this.right, this.bottom); - } - - /// Determine if 2 RECT are equal (deep compare) - public override bool Equals(object obj) - { - if (!(obj is Rect)) - { - return false; - } - - return (this == (RECT)obj); - } - - /// Return the HashCode for this struct (not garanteed to be unique) - public override int GetHashCode() - { - return this.left.GetHashCode() + this.top.GetHashCode() + this.right.GetHashCode() + this.bottom.GetHashCode(); - } - - public static bool operator ==(RECT rect1, RECT rect2) - { - return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom); - } - - public static bool operator !=(RECT rect1, RECT rect2) - { - return !(rect1 == rect2); - } - } +using System; +using System.Runtime.InteropServices; +using System.Windows; + +namespace Fluent.Metro.Native +{ +#pragma warning disable 1591 + [Serializable] + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal struct RECT + { + public int left; + public int top; + public int right; + public int bottom; + + public static readonly RECT Empty; + + public int Width + { + get { return Math.Abs(this.right - this.left); } // Abs needed for BIDI OS + } + + public int Height + { + get { return this.bottom - this.top; } + } + + public RECT(int left, int top, int right, int bottom) + { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public RECT(RECT rcSrc) + { + this.left = rcSrc.left; + this.top = rcSrc.top; + this.right = rcSrc.right; + this.bottom = rcSrc.bottom; + } + + public bool IsEmpty + { + get + { + // BUGBUG : On Bidi OS (hebrew arabic) left > right + return this.left >= this.right || this.top >= this.bottom; + } + } + + public override string ToString() + { + if (this == Empty) + { + return "RECT {Empty}"; + } + + return string.Format("RECT {{ left: {0} / top: {1} / right: {2} / bottom: {3} }}", this.left, this.top, this.right, this.bottom); + } + + /// Determine if 2 RECT are equal (deep compare) + public override bool Equals(object obj) + { + if (!(obj is Rect)) + { + return false; + } + + return (this == (RECT)obj); + } + + /// Return the HashCode for this struct (not garanteed to be unique) + public override int GetHashCode() + { + return this.left.GetHashCode() + this.top.GetHashCode() + this.right.GetHashCode() + this.bottom.GetHashCode(); + } + + public static bool operator ==(RECT rect1, RECT rect2) + { + return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom); + } + + public static bool operator !=(RECT rect1, RECT rect2) + { + return !(rect1 == rect2); + } + } } \ No newline at end of file diff --git a/Fluent.Ribbon/Properties/AssemblyInfo.cs b/Fluent.Ribbon/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..342db6e17 --- /dev/null +++ b/Fluent.Ribbon/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Markup; + +[assembly: AssemblyTitle("Fluent.Ribbon")] +[assembly: AssemblyDescription("Fluent.Ribbon")] + +[assembly: Guid("d849f751-e8f4-480d-acc0-6148eafcaafc")] + +[assembly: XmlnsPrefix("urn:fluent-ribbon", "fluent")] +[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent")] +[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent.Converters")] +[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent.Metro.Behaviours")] \ No newline at end of file diff --git a/Fluent/Properties/FluentStrongName.snk b/Fluent.Ribbon/Properties/FluentStrongName.snk similarity index 100% rename from Fluent/Properties/FluentStrongName.snk rename to Fluent.Ribbon/Properties/FluentStrongName.snk diff --git a/Fluent/RibbonCommands.cs b/Fluent.Ribbon/RibbonCommands.cs similarity index 96% rename from Fluent/RibbonCommands.cs rename to Fluent.Ribbon/RibbonCommands.cs index 7cbae8e66..cb5b9232c 100644 --- a/Fluent/RibbonCommands.cs +++ b/Fluent.Ribbon/RibbonCommands.cs @@ -1,20 +1,20 @@ -namespace Fluent -{ - using System.Windows.Input; - - /// - /// Class for several commands belonging to the Ribbon - /// - public static class RibbonCommands - { - private static readonly RoutedUICommand openBackstage = new RoutedUICommand("Open backstage", "OpenBackstage", typeof(RibbonCommands)); - - /// - /// Gets the value that represents the Open Backstage command - /// - public static RoutedCommand OpenBackstage - { - get { return openBackstage; } - } - } +namespace Fluent +{ + using System.Windows.Input; + + /// + /// Class for several commands belonging to the Ribbon + /// + public static class RibbonCommands + { + private static readonly RoutedUICommand openBackstage = new RoutedUICommand("Open backstage", "OpenBackstage", typeof(RibbonCommands)); + + /// + /// Gets the value that represents the Open Backstage command + /// + public static RoutedCommand OpenBackstage + { + get { return openBackstage; } + } + } } \ No newline at end of file diff --git a/Fluent/RibbonControlSizeDefinition.cs b/Fluent.Ribbon/RibbonControlSizeDefinition.cs similarity index 97% rename from Fluent/RibbonControlSizeDefinition.cs rename to Fluent.Ribbon/RibbonControlSizeDefinition.cs index c067920a9..57218704b 100644 --- a/Fluent/RibbonControlSizeDefinition.cs +++ b/Fluent.Ribbon/RibbonControlSizeDefinition.cs @@ -1,141 +1,141 @@ -namespace Fluent -{ - using System; - using System.ComponentModel; - using System.Linq; - using Fluent.Converters; - - /// - /// Class to map from to - /// - [TypeConverter(typeof(SizeDefinitionConverter))] - public struct RibbonControlSizeDefinition - { - private const int MaxSizeDefinitionParts = 3; - - /// - /// Creates a new instance - /// - public RibbonControlSizeDefinition(RibbonControlSize large, RibbonControlSize middle, RibbonControlSize small) - : this() - { - this.Large = large; - this.Middle = middle; - this.Small = small; - } - - /// - /// Creates a new instance - /// - public RibbonControlSizeDefinition(string sizeDefinition) - : this() - { - if (string.IsNullOrEmpty(sizeDefinition)) - { - this.Large = RibbonControlSize.Large; - this.Middle = RibbonControlSize.Large; - this.Small = RibbonControlSize.Large; - return; - } - - var splitted = sizeDefinition.Split(new[] { ' ', ',', ';', '-', '>' }, MaxSizeDefinitionParts, StringSplitOptions.RemoveEmptyEntries).ToList(); - - if (splitted.Count == 0) - { - this.Large = RibbonControlSize.Large; - this.Middle = RibbonControlSize.Large; - this.Small = RibbonControlSize.Large; - return; - } - - // Ensure that we got three sizes - for (var i = splitted.Count; i < MaxSizeDefinitionParts; i++) - { - splitted.Add(splitted[splitted.Count - 1]); - } - - this.Large = ToRibbonControlSize(splitted[0]); - this.Middle = ToRibbonControlSize(splitted[1]); - this.Small = ToRibbonControlSize(splitted[2]); - } - - /// - /// Gets or sets the value for large group sizes - /// - public RibbonControlSize Large { get; set; } - - /// - /// Gets or sets the value for middle group sizes - /// - public RibbonControlSize Middle { get; set; } - - /// - /// Gets or sets the value for small group sizes - /// - public RibbonControlSize Small { get; set; } - - /// - /// Converts from to - /// - public static implicit operator RibbonControlSizeDefinition(string sizeDefinition) - { - return new RibbonControlSizeDefinition(sizeDefinition); - } - - /// - /// Converts from to - /// - public static implicit operator string(RibbonControlSizeDefinition sizeDefinition) - { - return sizeDefinition.ToString(); - } - - /// - /// Converts from to - /// - public static RibbonControlSize ToRibbonControlSize(string ribbonControlSize) - { - RibbonControlSize result; - - return Enum.TryParse(ribbonControlSize, true, out result) - ? result - : RibbonControlSize.Large; - } - - /// - /// Gets the appropriate from , or depending on - /// - public RibbonControlSize GetSize(RibbonGroupBoxState ribbonGroupBoxState) - { - switch (ribbonGroupBoxState) - { - case RibbonGroupBoxState.Large: - return this.Large; - - case RibbonGroupBoxState.Middle: - return this.Middle; - - case RibbonGroupBoxState.Small: - return this.Small; - - case RibbonGroupBoxState.Collapsed: - case RibbonGroupBoxState.QuickAccess: - return this.Large; - - default: - return RibbonControlSize.Large; - } - } - - /// - /// Returns a string that represents the current object. - /// - /// - /// A string that represents the current object. - /// - public override string ToString() - { - return string.Format("{0} {1} {2}", this.Large, this.Middle, this.Small); - } - } +namespace Fluent +{ + using System; + using System.ComponentModel; + using System.Linq; + using Fluent.Converters; + + /// + /// Class to map from to + /// + [TypeConverter(typeof(SizeDefinitionConverter))] + public struct RibbonControlSizeDefinition + { + private const int MaxSizeDefinitionParts = 3; + + /// + /// Creates a new instance + /// + public RibbonControlSizeDefinition(RibbonControlSize large, RibbonControlSize middle, RibbonControlSize small) + : this() + { + this.Large = large; + this.Middle = middle; + this.Small = small; + } + + /// + /// Creates a new instance + /// + public RibbonControlSizeDefinition(string sizeDefinition) + : this() + { + if (string.IsNullOrEmpty(sizeDefinition)) + { + this.Large = RibbonControlSize.Large; + this.Middle = RibbonControlSize.Large; + this.Small = RibbonControlSize.Large; + return; + } + + var splitted = sizeDefinition.Split(new[] { ' ', ',', ';', '-', '>' }, MaxSizeDefinitionParts, StringSplitOptions.RemoveEmptyEntries).ToList(); + + if (splitted.Count == 0) + { + this.Large = RibbonControlSize.Large; + this.Middle = RibbonControlSize.Large; + this.Small = RibbonControlSize.Large; + return; + } + + // Ensure that we got three sizes + for (var i = splitted.Count; i < MaxSizeDefinitionParts; i++) + { + splitted.Add(splitted[splitted.Count - 1]); + } + + this.Large = ToRibbonControlSize(splitted[0]); + this.Middle = ToRibbonControlSize(splitted[1]); + this.Small = ToRibbonControlSize(splitted[2]); + } + + /// + /// Gets or sets the value for large group sizes + /// + public RibbonControlSize Large { get; set; } + + /// + /// Gets or sets the value for middle group sizes + /// + public RibbonControlSize Middle { get; set; } + + /// + /// Gets or sets the value for small group sizes + /// + public RibbonControlSize Small { get; set; } + + /// + /// Converts from to + /// + public static implicit operator RibbonControlSizeDefinition(string sizeDefinition) + { + return new RibbonControlSizeDefinition(sizeDefinition); + } + + /// + /// Converts from to + /// + public static implicit operator string(RibbonControlSizeDefinition sizeDefinition) + { + return sizeDefinition.ToString(); + } + + /// + /// Converts from to + /// + public static RibbonControlSize ToRibbonControlSize(string ribbonControlSize) + { + RibbonControlSize result; + + return Enum.TryParse(ribbonControlSize, true, out result) + ? result + : RibbonControlSize.Large; + } + + /// + /// Gets the appropriate from , or depending on + /// + public RibbonControlSize GetSize(RibbonGroupBoxState ribbonGroupBoxState) + { + switch (ribbonGroupBoxState) + { + case RibbonGroupBoxState.Large: + return this.Large; + + case RibbonGroupBoxState.Middle: + return this.Middle; + + case RibbonGroupBoxState.Small: + return this.Small; + + case RibbonGroupBoxState.Collapsed: + case RibbonGroupBoxState.QuickAccess: + return this.Large; + + default: + return RibbonControlSize.Large; + } + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + public override string ToString() + { + return string.Format("{0} {1} {2}", this.Large, this.Middle, this.Small); + } + } } \ No newline at end of file diff --git a/Fluent/RibbonGroupBoxPanel.cs b/Fluent.Ribbon/RibbonGroupBoxPanel.cs similarity index 96% rename from Fluent/RibbonGroupBoxPanel.cs rename to Fluent.Ribbon/RibbonGroupBoxPanel.cs index e8f85d6aa..2c4a703e4 100644 --- a/Fluent/RibbonGroupBoxPanel.cs +++ b/Fluent.Ribbon/RibbonGroupBoxPanel.cs @@ -1,19 +1,19 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Fluent -{ - /*class RibbonGroupBoxPanel - { - }*/ -} +#region Copyright and License Information +// Fluent Ribbon Control Suite +// http://fluent.codeplex.com/ +// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. +// +// Distributed under the terms of the Microsoft Public License (Ms-PL). +// The license is available online http://fluent.codeplex.com/license +#endregion +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Fluent +{ + /*class RibbonGroupBoxPanel + { + }*/ +} diff --git a/Fluent/RibbonLocalization.cs b/Fluent.Ribbon/RibbonLocalization.cs similarity index 97% rename from Fluent/RibbonLocalization.cs rename to Fluent.Ribbon/RibbonLocalization.cs index 021ff0ee1..983ad366a 100644 --- a/Fluent/RibbonLocalization.cs +++ b/Fluent.Ribbon/RibbonLocalization.cs @@ -1,2226 +1,2217 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.ComponentModel; -using System.Globalization; - -namespace Fluent -{ - /// - /// Contains localizable Ribbon's properties. - /// Set Culture property to change current Ribbon localization or - /// set properties independently to use your localization - /// - public class RibbonLocalization : INotifyPropertyChanged - { - #region Implementation of INotifyPropertyChanged - - /// - /// Occurs then property is changed - /// - public event PropertyChangedEventHandler PropertyChanged; - - // Raises PropertYChanegd event - private void RaisePropertyChanged(string propertyName) - { - if (this.PropertyChanged != null) - this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - - #region Culture - - private CultureInfo culture; - - /// - /// Gets or sets current culture used for localization - /// - public CultureInfo Culture - { - get { return this.culture; } - set - { - if (!Equals(this.culture, value)) - { - this.culture = value; - this.LoadCulture(this.culture); - this.RaisePropertyChanged("Culture"); - } - } - } - - #endregion - - #region Text of backstage button - - // Text of backstage button - private string backstageButtonText; - - /// - /// Gets or sets text of backstage button - /// - public string BackstageButtonText - { - get { return this.backstageButtonText; } - set - { - if (this.backstageButtonText != value) - { - this.backstageButtonText = value; - this.RaisePropertyChanged("BackstageButtonText"); - } - } - } - - #endregion - - #region KeyTip of backstage button - - // KeyTip of backstage button - private string backstageButtonKeyTip; - - /// - /// Gets or sets KeyTip of backstage button - /// - public string BackstageButtonKeyTip - { - get { return this.backstageButtonKeyTip; } - set - { - if (this.backstageButtonKeyTip != value) - { - this.backstageButtonKeyTip = value; - this.RaisePropertyChanged("BackstageButtonKeyTip"); - } - } - } - - #endregion - - #region Minimize Button ScreenTip Title - - // Minimize Button ScreenTip Title - private string minimizeButtonScreenTipTitle; - - /// - /// Minimize Button ScreenTip Title - /// - public string MinimizeButtonScreenTipTitle - { - get { return this.minimizeButtonScreenTipTitle; } - set - { - if (this.minimizeButtonScreenTipTitle != value) - { - this.minimizeButtonScreenTipTitle = value; - this.RaisePropertyChanged("MinimizeButtonScreenTipTitle"); - } - } - } - - #endregion - - #region Minimize Button ScreenTip Text - - // Minimize Button ScreenTip Text - private string minimizeButtonScreenTipText; - - /// - /// Minimize Button ScreenTip Text - /// - public string MinimizeButtonScreenTipText - { - get { return this.minimizeButtonScreenTipText; } - set - { - if (this.minimizeButtonScreenTipText != value) - { - this.minimizeButtonScreenTipText = value; - this.RaisePropertyChanged("MinimizeButtonScreenTipText"); - } - } - } - - #endregion - - #region Expand Button ScreenTip Title - - // Expand Button ScreenTip Title - private string expandButtonScreenTipTitle; - - /// - /// Expand Button ScreenTip Title - /// - public string ExpandButtonScreenTipTitle - { - get { return this.expandButtonScreenTipTitle; } - set - { - if (this.expandButtonScreenTipTitle != value) - { - this.expandButtonScreenTipTitle = value; - this.RaisePropertyChanged("ExpandButtonScreenTipTitle"); - } - } - } - - #endregion - - #region Expand Button ScreenTip Text - - // Expand Button ScreenTip Text - private string expandButtonScreenTipText; - - /// - /// Expand Button ScreenTip Text - /// - public string ExpandButtonScreenTipText - { - get { return this.expandButtonScreenTipText; } - set - { - if (this.expandButtonScreenTipText != value) - { - this.expandButtonScreenTipText = value; - this.RaisePropertyChanged("ExpandButtonScreenTipText"); - } - } - } - - #endregion - - #region Quick Access ToolBar DropDown Button ToolTip - - // Quick Access ToolBar DropDown Button ToolTip - private string quickAccessToolBarDropDownButtonTooltip; - - /// - /// Quick Access ToolBar DropDown Button ToolTip - /// - public string QuickAccessToolBarDropDownButtonTooltip - { - get { return this.quickAccessToolBarDropDownButtonTooltip; } - set - { - if (this.quickAccessToolBarDropDownButtonTooltip != value) - { - this.quickAccessToolBarDropDownButtonTooltip = value; - this.RaisePropertyChanged("QuickAccessToolBarDropDownButtonTooltip"); - } - } - } - - #endregion - - #region Quick Access ToolBar MoreControls Button ToolTip - - // Quick Access ToolBar MoreControls Button ToolTip - private string quickAccessToolBarMoreControlsButtonTooltip; - - /// - /// Quick Access ToolBar MoreControls Button ToolTip - /// - public string QuickAccessToolBarMoreControlsButtonTooltip - { - get { return this.quickAccessToolBarMoreControlsButtonTooltip; } - set - { - if (this.quickAccessToolBarMoreControlsButtonTooltip != value) - { - this.quickAccessToolBarMoreControlsButtonTooltip = value; - this.RaisePropertyChanged("QuickAccessToolBarMoreControlsButtonTooltip"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Header - - // Quick Access ToolBar Menu Header - private string quickAccessToolBarMenuHeader; - - /// - /// Quick Access ToolBar Menu Header - /// - public string QuickAccessToolBarMenuHeader - { - get { return this.quickAccessToolBarMenuHeader; } - set - { - if (this.quickAccessToolBarMenuHeader != value) - { - this.quickAccessToolBarMenuHeader = value; - this.RaisePropertyChanged("QuickAccessToolBarMenuHeader"); - } - } - } - - #endregion - - #region Quick Access ToolBar Context Menu Show Below - - // Quick Access ToolBar Minimize Quick Access Toolbar - private string quickAccessToolBarMenuShowBelow; - - /// - /// Quick Access ToolBar Minimize Quick Access Toolbar - /// - public string QuickAccessToolBarMenuShowBelow - { - get { return this.quickAccessToolBarMenuShowBelow; } - set - { - if (this.quickAccessToolBarMenuShowBelow != value) - { - this.quickAccessToolBarMenuShowBelow = value; - this.RaisePropertyChanged("QuickAccessToolBarMenuShowBelow"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Show Above - - // Quick Access ToolBar Menu Minimize Quick Access Toolbar - private string quickAccessToolBarMenuShowAbove; - - /// - /// Quick Access ToolBar Menu Minimize Quick Access Toolbar - /// - public string QuickAccessToolBarMenuShowAbove - { - get { return this.quickAccessToolBarMenuShowAbove; } - set - { - if (this.quickAccessToolBarMenuShowAbove != value) - { - this.quickAccessToolBarMenuShowAbove = value; - this.RaisePropertyChanged("QuickAccessToolBarMenuShowAbove"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Add Item - - // Quick Access ToolBar Menu Add Item - private string ribbonContextMenuAddItem; - - /// - /// Quick Access ToolBar Menu Add Item - /// - public string RibbonContextMenuAddItem - { - get { return this.ribbonContextMenuAddItem; } - set - { - if (this.ribbonContextMenuAddItem != value) - { - this.ribbonContextMenuAddItem = value; - this.RaisePropertyChanged("RibbonContextMenuAddItem"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Add Group - - // Quick Access ToolBar Menu Add Group - private string ribbonContextMenuAddGroup; - - /// - /// Quick Access ToolBar Menu Add Group - /// - public string RibbonContextMenuAddGroup - { - get { return this.ribbonContextMenuAddGroup; } - set - { - if (this.ribbonContextMenuAddGroup != value) - { - this.ribbonContextMenuAddGroup = value; - this.RaisePropertyChanged("RibbonContextMenuAddGroup"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Add Gallery - - // Quick Access ToolBar Menu Add Gallery - private string ribbonContextMenuAddGallery; - - /// - /// Quick Access ToolBar Menu Add Gallery - /// - public string RibbonContextMenuAddGallery - { - get { return this.ribbonContextMenuAddGallery; } - set - { - if (this.ribbonContextMenuAddGallery != value) - { - this.ribbonContextMenuAddGallery = value; - this.RaisePropertyChanged("RibbonContextMenuAddGallery"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Add Menu - - // Quick Access ToolBar Menu Add Menu - private string ribbonContextMenuAddMenu; - - /// - /// Quick Access ToolBar Menu Add Menu - /// - public string RibbonContextMenuAddMenu - { - get { return this.ribbonContextMenuAddMenu; } - set - { - if (this.ribbonContextMenuAddMenu != value) - { - this.ribbonContextMenuAddMenu = value; - this.RaisePropertyChanged("RibbonContextMenuAddMenu"); - } - } - } - - #endregion - - #region Quick Access ToolBar Menu Remove Item - - // Quick Access ToolBar Menu Remove Item - private string ribbonContextMenuRemoveItem; - - /// - /// Quick Access ToolBar Menu Remove Item - /// - public string RibbonContextMenuRemoveItem - { - get { return this.ribbonContextMenuRemoveItem; } - set - { - if (this.ribbonContextMenuRemoveItem != value) - { - this.ribbonContextMenuRemoveItem = value; - this.RaisePropertyChanged("RibbonContextMenuRemoveItem"); - } - } - } - - #endregion - - #region Ribbon Context Menu Customize Quick Access Toolbar - - // Ribbon Context Menu Customize Quick Access Toolbar - private string ribbonContextMenuCustomizeQuickAccessToolbar; - - /// - /// Ribbon Context Menu Customize Quick Access Toolbar - /// - public string RibbonContextMenuCustomizeQuickAccessToolBar - { - get { return this.ribbonContextMenuCustomizeQuickAccessToolbar; } - set - { - if (this.ribbonContextMenuCustomizeQuickAccessToolbar != value) - { - this.ribbonContextMenuCustomizeQuickAccessToolbar = value; - this.RaisePropertyChanged("RibbonContextMenuCustomizeQuickAccessToolBar"); - } - } - } - - #endregion - - #region Ribbon Context Menu Customize Ribbon - - // Ribbon Context Menu Customize Quick Access Toolbar - private string ribbonContextMenuCustomizeRibbon; - - /// - /// Ribbon Context Menu Customize Quick Access Toolbar - /// - public string RibbonContextMenuCustomizeRibbon - { - get { return this.ribbonContextMenuCustomizeRibbon; } - set - { - if (this.ribbonContextMenuCustomizeRibbon != value) - { - this.ribbonContextMenuCustomizeRibbon = value; - this.RaisePropertyChanged("RibbonContextMenuCustomizeRibbon"); - } - } - } - - #endregion - - #region Ribbon Context Menu Minimize Ribbon - - // Ribbon Context Menu Minimize Quick Access Toolbar - private string ribbonContextMenuMinimizeRibbon; - - /// - /// Ribbon Context Menu Minimize Quick Access Toolbar - /// - public string RibbonContextMenuMinimizeRibbon - { - get { return this.ribbonContextMenuMinimizeRibbon; } - set - { - if (this.ribbonContextMenuMinimizeRibbon != value) - { - this.ribbonContextMenuMinimizeRibbon = value; - this.RaisePropertyChanged("RibbonContextMenuMinimizeRibbon"); - } - } - } - - #endregion - - #region Ribbon Context Menu Show Below - - // Ribbon Context Menu Minimize Quick Access Toolbar - private string ribbonContextMenuShowBelow; - - /// - /// Ribbon Context Menu Minimize Quick Access Toolbar - /// - public string RibbonContextMenuShowBelow - { - get { return this.ribbonContextMenuShowBelow; } - set - { - if (this.ribbonContextMenuShowBelow != value) - { - this.ribbonContextMenuShowBelow = value; - this.RaisePropertyChanged("RibbonContextMenuShowBelow"); - } - } - } - - #endregion - - #region Ribbon Context Menu Show Above - - // Ribbon Context Menu Minimize Quick Access Toolbar - private string ribbonContextMenuShowAbove; - - /// - /// Ribbon Context Menu Minimize Quick Access Toolbar - /// - public string RibbonContextMenuShowAbove - { - get { return this.ribbonContextMenuShowAbove; } - set - { - if (this.ribbonContextMenuShowAbove != value) - { - this.ribbonContextMenuShowAbove = value; - this.RaisePropertyChanged("RibbonContextMenuShowAbove"); - } - } - } - - #endregion - - #region ScreenTipDisableReasonHeader - - // ScreenTip's Disable Reason Header - private string screenTipDisableReasonHeader; - - /// - /// Gets or sets ScreenTip's disable reason header - /// - public string ScreenTipDisableReasonHeader - { - get { return this.screenTipDisableReasonHeader; } - set - { - if (this.screenTipDisableReasonHeader != value) - { - this.screenTipDisableReasonHeader = value; - this.RaisePropertyChanged("ScreenTipDisableReasonHeader"); - } - } - } - - #endregion - - #region ScreenTipF1Label - - // ScreenTip's Disable Reason Header - private string screenTipF1LabelHeader; - - /// - /// Gets or sets ScreenTip's disable reason header - /// - public string ScreenTipF1LabelHeader - { - get { return this.screenTipF1LabelHeader; } - set - { - if (this.screenTipF1LabelHeader != value) - { - this.screenTipF1LabelHeader = value; - this.RaisePropertyChanged("ScreenTipF1LabelHeader"); - } - } - } - - #endregion - - #region Customize Status Bar - - // Text of backstage button - private string customizeStatusBar; - - /// - /// Gets or sets customize Status Bar - /// - public string CustomizeStatusBar - { - get { return this.customizeStatusBar; } - set - { - if (this.customizeStatusBar != value) - { - this.customizeStatusBar = value; - this.RaisePropertyChanged("CustomizeStatusBar"); - } - } - } - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonLocalization() - { - // Fallback values - this.LoadEnglish(); - - this.Culture = CultureInfo.CurrentUICulture; - } - - #endregion - - #region Methods - - // Coerce all localized values - private void LoadCulture(CultureInfo culture) - { - var language = culture.TwoLetterISOLanguageName; - - switch (language) - { - case "en": - this.LoadEnglish(); - break; - - case "ru": - this.LoadRussian(); - break; - - case "uk": - this.LoadUkrainian(); - break; - - case "fa": - this.LoadPersian(); - break; - - case "de": - this.LoadGerman(); - break; - - case "hu": - this.LoadHungarian(); - break; - - case "cs": - this.LoadCzech(); - break; - - case "fr": - this.LoadFrench(); - break; - - case "pl": - this.LoadPolish(); - break; - - case "ja": - this.LoadJapanese(); - break; - - case "nl": - this.LoadDutch(); - break; - case "pt": - { - if (culture.Name == "pt-BR") - { - this.LoadPortugueseBrazilian(); - } - else - { - this.LoadPortuguese(); - } - break; - } - - case "es": - this.LoadSpanish(); - break; - - //edit by gamegear.tw - //note: add TradChinese - case "zh": - if(culture.Name=="zh-tw") - { - this.LoadTradChinese(); - }else - { - this.LoadChinese(); - } - - break; - - case "sv": - this.LoadSwedish(); - break; - - case "sk": - this.LoadSlovak(); - break; - - case "ro": - this.LoadRomanian(); - break; - - case "it": - this.LoadItalian(); - break; - - case "ar": - this.LoadArabic(); - break; - - case "da": - this.LoadDanish(); - break; - - case "az": - this.LoadAzerbaijani(); - break; - - case "fi": - this.LoadFinnish(); - break; - - case "nb": - case "nn": - case "no": - this.LoadNorwegian(); - break; - - case "tr": - this.LoadTurkish(); - break; - - case "he": - this.LoadHebrew(); - break; - - case "ge": - this.LoadGreek(); - break; - - case "ko": - this.LoadKorean(); - break; - - case "lt": - this.LoadLithuanian(); - break; - - case "vi": - this.LoadVietnamese(); - break; - - case "si": - this.LoadSinhala(); - break; - - case "sl": - this.LoadSlovenian(); - break; - - case "ca": - this.LoadCatalan(); - break; - - case "et": - this.LoadEstonian(); - break; - } - - // Coerce all values - - this.RaisePropertyChanged("BackstageButtonText"); - this.RaisePropertyChanged("BackstageButtonKeyTip"); - - this.RaisePropertyChanged("MinimizeButtonScreenTipTitle"); - this.RaisePropertyChanged("MinimizeButtonScreenTipText"); - this.RaisePropertyChanged("ExpandButtonScreenTipTitle"); - this.RaisePropertyChanged("ExpandButtonScreenTipText"); - this.RaisePropertyChanged("QuickAccessToolBarDropDownButtonTooltip"); - this.RaisePropertyChanged("QuickAccessToolBarMoreControlsButtonTooltip"); - this.RaisePropertyChanged("QuickAccessToolBarMenuHeader"); - this.RaisePropertyChanged("QuickAccessToolBarMenuShowAbove"); - this.RaisePropertyChanged("QuickAccessToolBarMenuShowBelow"); - - this.RaisePropertyChanged("RibbonContextMenuAddItem"); - this.RaisePropertyChanged("RibbonContextMenuAddGroup"); - this.RaisePropertyChanged("RibbonContextMenuAddGallery"); - this.RaisePropertyChanged("RibbonContextMenuAddMenu"); - this.RaisePropertyChanged("RibbonContextMenuRemoveItem"); - this.RaisePropertyChanged("RibbonContextMenuCustomizeRibbon"); - this.RaisePropertyChanged("RibbonContextMenuCustomizeQuickAccessToolBar"); - this.RaisePropertyChanged("RibbonContextMenuShowAbove"); - this.RaisePropertyChanged("RibbonContextMenuShowBelow"); - this.RaisePropertyChanged("RibbonContextMenuMinimizeRibbon"); - - this.RaisePropertyChanged("ScreenTipDisableReasonHeader"); - this.RaisePropertyChanged("ScreenTipF1LabelHeader"); - this.RaisePropertyChanged("CustomizeStatusBar"); - } - - #endregion - - #region English - - private void LoadEnglish() - { - // Backstage button text & key tip - this.backstageButtonText = "File"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Collapse the Ribbon (Ctrl+F1)"; - this.minimizeButtonScreenTipText = "Need a bit more space? Collapse the ribbon so only the tab names show."; - this.expandButtonScreenTipTitle = "Pin the Ribbon (Ctrl+F1)"; - this.expandButtonScreenTipText = "Like seeing the ribbon? Keep it open while you work."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Customize Quick Access Toolbar"; - this.quickAccessToolBarMoreControlsButtonTooltip = "More controls"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Customize Quick Access Toolbar"; - this.quickAccessToolBarMenuShowAbove = "Show Above the Ribbon"; - this.quickAccessToolBarMenuShowBelow = "Show Below the Ribbon"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Add to Quick Access Toolbar"; // Button - this.ribbonContextMenuAddGroup = "Add Group to Quick Access Toolbar"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Add Gallery to Quick Access Toolbar"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Add Menu to Quick Access Toolbar"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Remove from Quick Access Toolbar"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customize Quick Access Toolbar..."; - this.ribbonContextMenuShowBelow = "Show Quick Access Toolbar Below the Ribbon"; - this.ribbonContextMenuShowAbove = "Show Quick Access Toolbar Above the Ribbon"; - this.ribbonContextMenuCustomizeRibbon = "Customize the Ribbon..."; - this.ribbonContextMenuMinimizeRibbon = "Collapse the Ribbon"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - //Screentips - this.screenTipDisableReasonHeader = "This command is currently disabled."; - this.screenTipF1LabelHeader = "Press F1 for help"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Customize Status Bar"; - } - - #endregion - - #region Russian - - private void LoadRussian() - { - this.backstageButtonText = "Файл"; - this.backstageButtonKeyTip = "Ф"; - - this.minimizeButtonScreenTipTitle = "Свернуть ленту (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Отображение или скрытие ленты\n\nКогда лента скрыта, отображаются только имена вкладок."; - this.expandButtonScreenTipTitle = "Развернуть ленту (Ctrl + F1)"; - this.expandButtonScreenTipText = "Отображение или скрытие ленты\n\nКогда лента скрыта, отображаются только имена вкладок."; - - this.quickAccessToolBarDropDownButtonTooltip = "Настройка панели быстрого доступа"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Другие элементы"; - this.quickAccessToolBarMenuHeader = "Настройка панели быстрого доступа"; - this.quickAccessToolBarMenuShowAbove = "Разместить над лентой"; - this.quickAccessToolBarMenuShowBelow = "Разместить под лентой"; - - this.ribbonContextMenuAddItem = "Добавить на панель быстрого доступа"; - this.ribbonContextMenuAddGroup = "Добавить группу на панель быстрого доступа"; - this.ribbonContextMenuAddGallery = "Добавить коллекцию на панель быстрого доступа"; - this.ribbonContextMenuAddMenu = "Добавить меню на панель быстрого доступа"; - this.ribbonContextMenuRemoveItem = "Удалить с панели быстрого доступа"; - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Настройка панели быстрого доступа..."; - this.ribbonContextMenuShowBelow = "Разместить панель быстрого доступа под лентой"; - this.ribbonContextMenuShowAbove = "Разместить панель быстрого доступа над лентой"; - this.ribbonContextMenuCustomizeRibbon = "Настройка ленты..."; - this.ribbonContextMenuMinimizeRibbon = "Свернуть ленту"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - this.screenTipDisableReasonHeader = "В настоящее время эта команда отключена."; - - this.customizeStatusBar = "Настройка строки состояния"; - } - - #endregion - - #region Ukrainian - - private void LoadUkrainian() - { - // Backstage button text & key tip - this.backstageButtonText = "Файл"; - this.backstageButtonKeyTip = "Ф"; - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Сховати Стрічку (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Показати або сховати Стрічку\n\nКоли стрічка схована, видно тільки назви вкладок"; - this.expandButtonScreenTipTitle = "Показати Стрічку (Ctrl + F1)"; - this.expandButtonScreenTipText = "Показати або сховати Стрічку\n\nКоли стрічка схована, видно тільки назви вкладок"; - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Налаштувати Панель Інструментів Швидкого Доступу"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Більше елементів"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Налаштувати Панель Інструментів Швидкого Доступу"; - this.quickAccessToolBarMenuShowAbove = "Показати Поверх Стрічки"; - this.quickAccessToolBarMenuShowBelow = "Показати Знизу Стрічки"; - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Додати до Панелі Інструментів Швидкого Доступу"; // Button - this.ribbonContextMenuAddGroup = "Додати Групу до Панелі Інструментів Швидкого Доступу"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Додати Галерею до Панелі Інструментів Швидкого Доступу"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Додати Меню до Панелі Інструментів Швидкого Доступу"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Видалити з Панелі Інструментів Швидкого Доступу"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Налаштувати Панель Інструментів Швидкого Доступу..."; - this.ribbonContextMenuShowBelow = "Показати Панель Інструментів Швидкого Доступу Знизу Стрічки"; - this.ribbonContextMenuShowAbove = "Показати Панель Інструментів Швидкого Доступу Поверх Стрічки"; - this.ribbonContextMenuCustomizeRibbon = "Налаштувати Стрічку..."; - this.ribbonContextMenuMinimizeRibbon = "Зменшити Стрічку"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Ця команда на даний момент недоступна."; - } - - #endregion - - #region Persian - - private void LoadPersian() - { - // Backstage button text & key tip - this.backstageButtonText = "فایل"; - this.backstageButtonKeyTip = "ف"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "کوچک کردن نوار (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "نمایش یا مخفی کردن نوار\n\nهنگامی که نوار مخفی است، تنها\nنام زبانه ها نمایش داده می شود."; - this.expandButtonScreenTipTitle = "بزرگ کردن نوار (Ctrl + F1)"; - this.expandButtonScreenTipText = "نمایش یا مخفی کردن نوار\n\nهنگامی که نوار مخفی است، تنها\nنام زبانه ها نمایش داده می شود."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "دلخواه سازی میله ابزار دسترسی سریع"; - this.quickAccessToolBarMoreControlsButtonTooltip = "ابزارهای دیگر"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "دلخواه سازی میله ابزار دسترسی سریع"; - this.quickAccessToolBarMenuShowAbove = "نمایش در بالای نوار"; - this.quickAccessToolBarMenuShowBelow = "نمایش در پایین نوار"; - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "اضافه کردن به میله ابزار دسترسی سریع"; // Button - this.ribbonContextMenuAddGroup = "اضافه کردن گروه به میله ابزار دسترسی سریع"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "اضافه کردن گالری به میله ابزار دسترسی سریع"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "اضاقه کردن منو به میله ابزار دسترسی سریع"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "حذف از میله ابزار دسترسی سریع"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "دلخواه سازی میله ابزار دسترسی سریع..."; - this.ribbonContextMenuShowBelow = "نمایش میله ابزار دسترسی سریع در پایین نوار"; - this.ribbonContextMenuShowAbove = "نمایش میله ابزار دسترسی سریع در بالای نوار"; - this.ribbonContextMenuCustomizeRibbon = "دلخواه سازی نوار..."; - this.ribbonContextMenuMinimizeRibbon = "کوچک کردن نوار"; - } - - #endregion - - #region German - - private void LoadGerman() - { - // Backstage button text & key tip - this.backstageButtonText = "Datei"; - this.backstageButtonKeyTip = "D"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Menüband minimieren (Strg+F1)"; - this.minimizeButtonScreenTipText = "Sie benötigen etwas mehr Platz? Reduzieren Sie das Menüband, sodass nur die Registerkartennamen angezeigt werden."; - this.expandButtonScreenTipTitle = "Menüband erweitern (Strg+F1)"; - this.expandButtonScreenTipText = "Ist es Ihnen lieber, wenn Sie das Menüband sehen? Lassen Sie es während der Arbeit geöffnet."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Symbolleiste für den Schnellzugriff anpassen"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Weitere Befehle…"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Symbolleiste für den Schnellzugriff anpassen"; - this.quickAccessToolBarMenuShowAbove = "Über dem Menüband anzeigen"; - this.quickAccessToolBarMenuShowBelow = "Unter dem Menüband anzeigen"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Zur Symbolleiste für den Schnellzugriff hinzufügen"; // Button - this.ribbonContextMenuAddGroup = "Gruppe zur Symbolleiste für den Schnellzugriff hinzufügen"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Katalog zur Symbolleiste für den Schnellzugriff hinzufügen"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Zur Symbolleiste für den Schnellzugriff hinzufügen"; // By dashed splitter in context menu - - this.ribbonContextMenuRemoveItem = "Aus Symbolleiste für den Schnellzugriff entfernen"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Symbolleiste für den Schnellzugriff anpassen..."; - this.ribbonContextMenuShowBelow = "Symbolleiste für den Schnellzugriff unter dem Menüband anzeigen"; - this.ribbonContextMenuShowAbove = "Symbolleiste für den Schnellzugriff über dem Menüband anzeigen"; - this.ribbonContextMenuCustomizeRibbon = "Menüband anpassen..."; - this.ribbonContextMenuMinimizeRibbon = "Menüband minimieren"; - - //Screentips - this.screenTipDisableReasonHeader = "Diese Funktion ist momentan deaktiviert."; - this.screenTipF1LabelHeader = "Drücken Sie F1 für die Hilfe"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Statusleiste anpassen"; - } - - #endregion - - #region Hungarian - - private void LoadHungarian() - { - // Backstage button text & key tip - this.backstageButtonText = "Fájl"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "A menüszalag összecsukása (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Csak a lapnevek megjelenítése a menüszalagon"; - this.expandButtonScreenTipTitle = "Menüszalag kibontása (Ctrl + F1)"; - this.expandButtonScreenTipText = "A menüszalag megjelenítése úgy, hogy egy parancsra kattintás után is látható maradjon"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Gyorselérési eszköztár testreszabása"; - this.quickAccessToolBarMoreControlsButtonTooltip = "További vezérlők"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Gyorselérési eszköztár testreszabása"; - this.quickAccessToolBarMenuShowAbove = "Megjelenítés a menüszalag alatt"; - this.quickAccessToolBarMenuShowBelow = "Megjelenítés a menüszalag felett"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Felvétel a gyorselérési eszköztárra"; // Button - this.ribbonContextMenuAddGroup = "Felvétel a gyorselérési eszköztárra"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Gyűjtemény felvétele a gyorselérési eszköztárra"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Felvétel a gyorselérési eszköztárra"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Eltávolítás a gyorselérési eszköztárról"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Gyorselérési eszköztár testreszabása..."; - this.ribbonContextMenuShowBelow = "A gyorselérési eszköztár megjelenítése a menüszalag alatt"; - this.ribbonContextMenuShowAbove = "A gyorselérési eszköztár megjelenítése a menüszalag felett"; - this.ribbonContextMenuCustomizeRibbon = "Menüszalag testreszabása..."; - this.ribbonContextMenuMinimizeRibbon = " A menüszalag összecsukása"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Ez a parancs jelenleg nem használható."; - } - - #endregion - - #region Czech - - private void LoadCzech() - { - // Backstage button text & key tip - this.backstageButtonText = "Soubor"; - this.backstageButtonKeyTip = "S"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Skrýt pás karet (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Zobrazit nebo skrýt pás karet\n\nJe-li pás karet skrytý, jsou zobrazeny pouze názvy karet"; - this.expandButtonScreenTipTitle = "Zobrazit pás karet (Ctrl + F1)"; - this.expandButtonScreenTipText = "Zobrazit nebo skrýt pás karet\n\nJe-li pás karet skrytý, jsou zobrazeny pouze názvy karet"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Přizpůsobit panel nástrojů Rychlý přístup"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Další příkazy"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Přizpůsobit panel nástrojů Rychlý přístup"; - this.quickAccessToolBarMenuShowAbove = "Zobrazit nad pásem karet"; - this.quickAccessToolBarMenuShowBelow = "Zobrazit pod pásem karet"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Přidat na panel nástrojů Rychlý přístup"; // Button - this.ribbonContextMenuAddGroup = "Přidat na panel nástrojů Rychlý přístup"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Přidat galerii na panel nástrojů Rychlý přístup"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Přidat na panel nástrojů Rychlý přístup"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Odebrat z panelu nástrojů Rychlý přístup"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Přizpůsobit panel nástrojů Rychlý přístup..."; - this.ribbonContextMenuShowBelow = "Zobrazit panel nástrojů Rychlý přístup pod pásem karet"; - this.ribbonContextMenuShowAbove = "Zobrazit panel nástrojů Rychlý přístup nad pásem karet"; - this.ribbonContextMenuCustomizeRibbon = "Přizpůsobit pás karet..."; - this.ribbonContextMenuMinimizeRibbon = "Skrýt pás karet"; - - //Screentips - this.screenTipDisableReasonHeader = "Tento příkaz je aktuálně zakázán."; - this.screenTipF1LabelHeader = "Stiskni F1 pro nápovědu"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Přizpůsobit Status Bar"; - } - - #endregion - - #region French - - private void LoadFrench() - { - // Backstage button text & key tip - this.backstageButtonText = "Fichier"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimiser le Ruban (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Afficher ou masquer le Ruban \n\nQuand le Ruban est masqué, seul les noms sont affichés"; - this.expandButtonScreenTipTitle = "Agrandir le Ruban (Ctrl + F1)"; - this.expandButtonScreenTipText = "Afficher ou masquer le Ruban \n\nQuand le Ruban est masqué, seul les noms sont affichés"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personnaliser la barre d'outils Accès Rapide"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Plus de contrôles"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personnaliser la barre d'outil Accès Rapide"; - this.quickAccessToolBarMenuShowAbove = "Afficher au dessus du Ruban"; - this.quickAccessToolBarMenuShowBelow = "Afficher en dessous du Ruban"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Ajouter un élément à la barre d'outils Accès Rapide"; // Button - this.ribbonContextMenuAddGroup = "Ajouter un groupe à la barre d'outils Accès Rapide"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Ajouter une galerie à la barre d'outils Accès Rapide"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Ajouter un menu à la barre d'outils Accès Rapide"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Supprimer de la barre d'outils Accès Rapide"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personnaliser la barre d'outils Accès Rapide..."; - this.ribbonContextMenuShowBelow = "Afficher la barre d'outils Accès Rapide en dessous du Ruban"; - this.ribbonContextMenuShowAbove = "Afficher la barre d'outils Accès Rapide au dessus du Ruban"; - this.ribbonContextMenuCustomizeRibbon = "Personnaliser le Ruban..."; - this.ribbonContextMenuMinimizeRibbon = "Minimiser le Ruban"; - this.customizeStatusBar = "Personnaliser la barre de statut"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - this.screenTipDisableReasonHeader = "Cette commande est actuellement désactivée."; - } - - #endregion - - #region Polish - - private void LoadPolish() - { - // Backstage button text & key tip - this.backstageButtonText = "Plik"; - this.backstageButtonKeyTip = "P"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimalizuj Wstążkę (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Pokazuje lub ukrywa Wstążkę\n\nGdy Wstążka jest ukryta, tylko nazwy zakładek są widoczne"; - this.expandButtonScreenTipTitle = "Rozwiń Wstążkę (Ctrl + F1)"; - this.expandButtonScreenTipText = "Pokazuje lub ukrywa Wstążkę\n\nGdy Wstążka jest ukryta, tylko nazwy zakładek są widoczne"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Dostosuj pasek narzędzi Szybki dostęp"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Więcej poleceń..."; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Dostosuj pasek narzędzi Szybki dostęp"; - this.quickAccessToolBarMenuShowAbove = "Pokaż powyżej Wstążki"; - this.quickAccessToolBarMenuShowBelow = "Pokaż poniżej Wstążki"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Dodaj do paska narzędzi Szybki dostęp"; // Button - this.ribbonContextMenuAddGroup = "Dodaj Grupę do paska narzędzi Szybki dostęp"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Dodaj Galerię do paska narzędzi Szybki dostęp"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Dodaj do paska narzędzi Szybki dostęp"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Usuń z paska narzędzi Szybki dostęp"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Dostosuj pasek narzędzi Szybki dostęp..."; - this.ribbonContextMenuShowBelow = "Pokaż pasek Szybki dostęp poniżej Wstążki"; - this.ribbonContextMenuShowAbove = "Pokaż pasek Szybki dostęp powyżej Wstążki"; - this.ribbonContextMenuCustomizeRibbon = "Dostosuj Wstążkę..."; - this.ribbonContextMenuMinimizeRibbon = "Minimalizuj Wstążkę"; - } - - #endregion - - #region Japanese - - private void LoadJapanese() - { - // Backstage button text & key tip - this.backstageButtonText = "ファイル"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "リボンの最小化 (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "リボンの表示/非表示を切り替えます。\n\nリボンを非表示にすると、タブ名のみが表示されます。"; - this.expandButtonScreenTipTitle = "リボンの展開 (Ctrl + F1)"; - this.expandButtonScreenTipText = "リボンの表示/非表示を切り替えます。\n\nリボンを非表示にすると、タブ名のみが表示されます。"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "クイック アクセス ツール バーのユーザー設定"; - this.quickAccessToolBarMoreControlsButtonTooltip = "その他のボタン"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "クイック アクセス ツール バーのユーザー設定"; - this.quickAccessToolBarMenuShowAbove = "リボンの上に表示"; - this.quickAccessToolBarMenuShowBelow = "リボンの下に表示"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "クイック アクセス ツール バーに追加"; // Button - this.ribbonContextMenuAddGroup = "グループをクイック アクセス ツール バーに追加"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "ギャラリーをクイック アクセス ツール バーに追加"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "メニューをクイック アクセス ツール バーに追加"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "クイック アクセス ツール バーから削除"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "クイック アクセス ツール バーのユーザー設定..."; - this.ribbonContextMenuShowBelow = "クイック アクセス ツール バーをリボンの下に表示"; - this.ribbonContextMenuShowAbove = "クイック アクセス ツール バーをリボンの上に表示"; - this.ribbonContextMenuCustomizeRibbon = "リボンのユーザー設定..."; - this.ribbonContextMenuMinimizeRibbon = "リボンの最小化"; - this.customizeStatusBar = "ステータス バーのユーザー設定"; - - this.screenTipDisableReasonHeader = "このコマンドは現在無効になっています"; - } - - #endregion - - #region Dutch - - private void LoadDutch() - { - // Backstage button text & key tip - this.backstageButtonText = "Bestand"; - this.backstageButtonKeyTip = "B"; - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Het lint minimaliseren (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Verberg of laat het lint zien\n\nWanneer het lint verborgen is, zijn alleen de tabulatie namen zichtbaar"; - this.expandButtonScreenTipTitle = "Het lint Maximaliseren (Ctrl + F1)"; - this.expandButtonScreenTipText = "Verberg of laat het lint zien\n\nWanneer het lint verborgen is, zijn alleen de tabulatie namen zichtbaar"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Werkbalk snelle toegang aanpassen"; - this.quickAccessToolBarMoreControlsButtonTooltip = "meer opdrachten"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = " Werkbalk snelle toegang aanpassen "; - this.quickAccessToolBarMenuShowAbove = "Boven het lint weergeven"; - this.quickAccessToolBarMenuShowBelow = "beneden het lint weergeven"; - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Menu toevoegen aan werkbalk snelle toegang"; // Button - this.ribbonContextMenuAddGroup = "Groep toevoegen aan werkbalk snelle toegang"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Galerij toevoegen aan werkbalk snelle toegang"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = " Menu toevoegen aan werkbalk snelle toegang "; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = " Verwijder uit werkbalk snelle toegang "; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customize Quick Access Toolbar..."; - this.ribbonContextMenuShowBelow = " Werkbalk snelle toegang onder het lint weergeven"; - this.ribbonContextMenuShowAbove = " Werkbalk snelle toegang boven het lint weergeven "; - this.ribbonContextMenuCustomizeRibbon = "Lint aanpassen..."; - this.ribbonContextMenuMinimizeRibbon = " Het lint minimaliseren"; - } - - #endregion - - #region Brazilian - - private void LoadPortugueseBrazilian() - { - // Backstage button text & key tip - this.backstageButtonText = "Arquivo"; - this.backstageButtonKeyTip = "A"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimizar o Ribbon (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Mostrar ou esconder o Ribbon\n\nQuando o Ribbon estiver escondido, somente o nome das abas serão mostrados"; - this.expandButtonScreenTipTitle = "Expandir o Ribbon (Ctrl + F1)"; - this.expandButtonScreenTipText = "Mostrar ou esconder o Ribbon\n\nQuando o Ribbon estiver escondido, somente o nome das abas serão mostrados"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Customizar Barra de acesso rápido"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Mais controles"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = " Customizar Barra de acesso rápido"; - this.quickAccessToolBarMenuShowAbove = "Mostrar acima do Ribbon"; - this.quickAccessToolBarMenuShowBelow = "Mostrar abaixo do Ribbon"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Adicionar para Barra de acesso rápido"; // Button - this.ribbonContextMenuAddGroup = " Adicionar o grupo para Barra de acesso rápido"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Adicionar a galeria para Barra de acesso rápido"; - // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = " Adicionar o menu para Barra de acesso rápido"; - // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Remover da Barra de acesso rápido"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customizar Barra de acesso rápido..."; - this.ribbonContextMenuShowBelow = "Mostrar Barra de acesso rápido abaixo do Ribbon"; - this.ribbonContextMenuShowAbove = "Mostrar Barra de acesso rápido acima do Ribbon"; - this.ribbonContextMenuCustomizeRibbon = "Customizar o Ribbon..."; - this.ribbonContextMenuMinimizeRibbon = "Minimizar o Ribbon"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Este comando está desativado."; - } - - #endregion - - #region Spanish - - private void LoadSpanish() - { - // Backstage button text & key tip - this.backstageButtonText = "Archivo"; - this.backstageButtonKeyTip = "A"; - - // See right-top corner... (two different tooltips must be if you press it) - // TRANSLATOR'S NOTE: This block is not shown at Windows 7's Apps (WordPad or Paint) - this.minimizeButtonScreenTipTitle = "Minimizar la cinta (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Muestra u oculta la cinta\n\nCuando la cinta está oculta, sólo se muestran los nombres de las pestañas"; - this.expandButtonScreenTipTitle = "Expandir la cinta (Ctrl + F1)"; - this.expandButtonScreenTipText = "Muestra u oculta la cinta\n\nCuando la cinta está oculta, sólo se muestran los nombres de las pestañas"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personalizar barra de herramientas de acceso rápido"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Más controles"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personalizar barra de herramientas de acceso rápido"; - this.quickAccessToolBarMenuShowAbove = "Mostrar sobre la cinta"; - this.quickAccessToolBarMenuShowBelow = "Mostrar bajo la cinta"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Agregar a la barra de herramientas de acceso rápido"; // Button - this.ribbonContextMenuAddGroup = "Agregar grupo a la barra de herramientas de acceso rápido"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Agregar galería a la barra de herramientas de acceso rápido"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Agregar menú a la barra de herramientas de acceso rápido"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Quitar de la barra de herramientas de acceso rápido"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizar la barra de herramientas de acceso rápido..."; - this.ribbonContextMenuShowBelow = "Mostrar barra de herramientas de acceso rápido bajo la cinta"; - this.ribbonContextMenuShowAbove = "Mostrar barra de herramientas de acceso rápido sobre la cinta"; - this.ribbonContextMenuCustomizeRibbon = "Personalizar la cinta..."; - this.ribbonContextMenuMinimizeRibbon = "Minimizar la cinta"; - - //Screentips - this.screenTipDisableReasonHeader = "Este comando está desactivado actualmente"; - this.screenTipF1LabelHeader = "Pulse F1 para obtener más ayuda"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Personalizar barra de estado"; - } - - #endregion - - #region Chinese - - private void LoadChinese() - { - // Backstage button text & key tip - this.backstageButtonText = "文件"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "功能区最小化 (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "仅显示功能区上的选项卡名称。单击选项卡可显示命令。"; - this.expandButtonScreenTipTitle = "展开功能区 (Ctrl + F1)"; - this.expandButtonScreenTipText = "始终显示功能区选项卡和命令。"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "自定义快速访问具栏"; - this.quickAccessToolBarMoreControlsButtonTooltip = "其他命令"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "自定义快速访问工具栏"; - this.quickAccessToolBarMenuShowAbove = "在功能区上方显示"; - this.quickAccessToolBarMenuShowBelow = "在功能区下方显示"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "添加到快速访问工具栏"; // Button - this.ribbonContextMenuAddGroup = "在快速访问工具栏中添加组"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "在快速访问工具栏中添加样式"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "在快速访问工具栏中添加菜单"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "在快速访问工具栏中移除"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "自定义快速访问工具栏..."; - this.ribbonContextMenuShowBelow = "在功能区下方显示快速访问工具栏"; - this.ribbonContextMenuShowAbove = "在功能区上方显示快速访问工具栏"; - this.ribbonContextMenuCustomizeRibbon = "自定义功能区..."; - this.ribbonContextMenuMinimizeRibbon = "功能区最小化"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "此命令当前已被禁用。"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "自定义状态栏"; - } - - #endregion - - #region Swedish - - private void LoadSwedish() - { - // Backstage button text & key tip - this.backstageButtonText = "Arkiv"; - this.backstageButtonKeyTip = "A"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimera menyfliksområdet (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Visa eller göm menyfliksområdet \n\nNär menyfliksområdet är dolt, visas endast flikarna"; - this.expandButtonScreenTipTitle = "Expandera menyfliksområdet (Ctrl + F1)"; - this.expandButtonScreenTipText = "Visa eller göm menyfliksområdet \n\nNär menyfliksområdet är dolt, visas endast flikarna"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Anpassa verktygsfältet Snabbåtkomst "; - this.quickAccessToolBarMoreControlsButtonTooltip = "Fler kommandon"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = " Anpassa verktygsfältet Snabbåtkomst"; - this.quickAccessToolBarMenuShowAbove = "Visa ovanför menyfliksområdet"; - this.quickAccessToolBarMenuShowBelow = "Visa under menyfliksområdet"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Lägg till i verktygsfältet Snabbåtkomst"; // Button - this.ribbonContextMenuAddGroup = "Lägg till i verktygsfältet Snabbåtkomst"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Lägg till galleriet i verktygsfältet Snabbåtkomst"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = " Lägg till menyn i verktygsfältet Snabbåtkomst "; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Ta bort från verktygsfältet Snabbåtkomst"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Anpassa verktygsfältet Snabbåtkomst..."; - this.ribbonContextMenuShowBelow = " Visa verktygsfältet Snabbåtkomst under menyfliksområdet"; - this.ribbonContextMenuShowAbove = " Visa verktygsfältet Snabbåtkomst ovanför menyfliksområdet "; - this.ribbonContextMenuCustomizeRibbon = "Anpassa menyfliksområdet..."; - this.ribbonContextMenuMinimizeRibbon = "Minimera menyfliksområdet"; - } - - #endregion - - #region Slovak - - private void LoadSlovak() - { - // Backstage button text & key tip - this.backstageButtonText = "Súbor"; - this.backstageButtonKeyTip = "S"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Skryť pás s nástrojmi (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Zobraziť alebo skryť pás s nástrojmi\n\nKeď je pás s nástrojmi skrytý, sú zobrazené iba názvy kariet"; - this.expandButtonScreenTipTitle = "Zobraziť pás s nástrojmi (Ctrl + F1)"; - this.expandButtonScreenTipText = " Zobraziť alebo skryť pás s nástrojmi\n\nKeď je pás s nástrojmi skrytý, sú zobrazené iba názvy kariet "; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Prispôsobenie panela s nástrojmi Rýchly prístup"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Ďalšie príkazy"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Prispôsobenie panela s nástrojmi Rýchly prístup"; - this.quickAccessToolBarMenuShowAbove = " Zobraziť nad pásom s nástrojmi "; - this.quickAccessToolBarMenuShowBelow = "Zobraziť pod pásom s nástrojmi"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Pridať na panel s nástrojmi Rýchly prístup"; // Button - this.ribbonContextMenuAddGroup = " Pridať na panel s nástrojmi Rýchly prístup "; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = " Pridať galériu do panela s nástrojmi Rýchly prístup "; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Pridať na panel s nástrojmi Rýchly prístup"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Odstrániť z panela s nástrojmi Rýchly prístup "; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = " Prispôsobenie panela s nástrojmi Rýchly prístup..."; - this.ribbonContextMenuShowBelow = "Panel s nástrojmi Rýchly prístup zobraziť pod panelom s nástrojmi"; - this.ribbonContextMenuShowAbove = "Panel s nástrojmi Rýchly prístup zobraziť nad panelom s nástrojmi "; - this.ribbonContextMenuCustomizeRibbon = "Prispôsobenie panela s nástrojmi Rýchly prístup..."; - this.ribbonContextMenuMinimizeRibbon = "Minimalizovať pás s nástrojmi"; - } - - #endregion - - #region Romanian - - private void LoadRomanian() - { - // Backstage button text & key tip - this.backstageButtonText = "Fișier"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimizează Ribbon-ul (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Afișează sau ascunde Ribbon-ul\nCând Ribbon-ul este ascuns, sunt afișate doar numele taburilor"; - this.expandButtonScreenTipTitle = "Expandează Ribbon-ul (Ctrl + F1)"; - this.expandButtonScreenTipText = "Afișează sau ascunde Ribbon-ul\nCând Ribbon-ul este ascuns, sunt afișate doar numele taburilor"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personalizează Bara de Acces Rapid"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Mai multe controale"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personalizează Bara de Acces Rapid"; - this.quickAccessToolBarMenuShowAbove = "Afișează peste Ribbon"; - this.quickAccessToolBarMenuShowBelow = "Afișează sub Ribbon"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Adaugă la Bara de Acess Rapid"; // Button - this.ribbonContextMenuAddGroup = "Adaugă Grupul la Bara de Acess Rapid"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Adaugă Galeria la Bara de Acess Rapid"; - // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Adaugă Meniul la Bara de Acess Rapid"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Eimină din Bara de Acess Rapid"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizează Bara de Acces Rapid..."; - this.ribbonContextMenuShowBelow = "Afișează Bara de Acces Rapid sub Ribbon"; - this.ribbonContextMenuShowAbove = "Afișează Bara de Acces Rapid peste Ribbon"; - this.ribbonContextMenuCustomizeRibbon = "Personalizează Ribbon-ul..."; - this.ribbonContextMenuMinimizeRibbon = "Minimizează Ribbon-ul..."; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Această comandă nu este disponibilă momentan."; - } - - #endregion - - #region Italian - - private void LoadItalian() - { - // Backstage button text & key tip - this.backstageButtonText = "File"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Riduci a icona barra multifunzione (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Consente di visualizzare solo i nomi delle schede nella barra multifunzione."; - this.expandButtonScreenTipTitle = "Espandi la barra multifunzione (Ctrl + F1)"; - this.expandButtonScreenTipText = "Visualizza la barra multifunzione in modo che rimanga sempre espansa, anche se l’utente ha fatto click su un comando."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personalizza barra di accesso rapido"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Altri comandi…"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personalizza barra di accesso rapido"; - this.quickAccessToolBarMenuShowAbove = "Mostra sopra la barra multifunzione"; - this.quickAccessToolBarMenuShowBelow = "Mostra sotto la barra multifunzione"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Aggiungi alla barra di accesso rapido"; // Button - this.ribbonContextMenuAddGroup = "Aggiungi gruppo alla barra di accesso rapido"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Aggiungi raccolta alla barra di accesso rapido"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Aggiungi menu alla barra di accesso rapido"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Rimuovi dalla barra di accesso rapido"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizza barra di accesso rapido..."; - this.ribbonContextMenuShowBelow = "Mostra la barra di accesso rapido sotto la barra multifunzione"; - this.ribbonContextMenuShowAbove = "Mostra la barra di accesso rapido sopra la barra multifunzione"; - this.ribbonContextMenuCustomizeRibbon = "Personalizza barra multifunzione..."; - this.ribbonContextMenuMinimizeRibbon = "Riduci a icona barra multifunzione"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Questo commando è disattivato."; - } - - #endregion - - #region Arabic - - private void LoadArabic() - { - // Backstage button text & key tip - this.backstageButtonText = "ملف "; - this.backstageButtonKeyTip = "م "; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "(Ctrl + F1)تصغير الشريط "; - this.minimizeButtonScreenTipText = "إظهار أسماء علامات التبويب فقط على الشريط."; - this.expandButtonScreenTipTitle = "(Ctrl + F1)توسيع الشريط "; - this.expandButtonScreenTipText = "إظهار الشريط بحيث يكون موسعاً دائماً حتى بعد النقر فوق أمر."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "تخصيص شريط أدوات الوصول السريع"; - this.quickAccessToolBarMoreControlsButtonTooltip = "أوامر إضافية"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "تخصيص شريط أدوات الوصول السريع"; - this.quickAccessToolBarMenuShowAbove = "إظهار أعلى الشريط"; - this.quickAccessToolBarMenuShowBelow = "إظهار أسفل الشريط"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "إضافة إلى شريط أدوات الوصول السريع"; // Button - this.ribbonContextMenuAddGroup = "إضافة إلى شريط أدوات الوصول السريع"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "إضافة إلى شريط أدوات الوصول السريع"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "إضافة إلى شريط أدوات الوصول السريع"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "إزالة إلى شريط أدوات الوصول السريع"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "تخصيص شريط أدوات الوصول السريع..."; - this.ribbonContextMenuShowBelow = "إظهار شريط أدوات الوصول السريع أسفل الشريط"; - this.ribbonContextMenuShowAbove = "إظهار شريط أدوات الوصول السريع أعلى الشريط"; - this.ribbonContextMenuCustomizeRibbon = "تخصيص الشريط..."; - this.ribbonContextMenuMinimizeRibbon = "تصغير الشريط"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "تم حالياً تعطيل هذا الأمر."; - } - - #endregion - - #region Danish - - private void LoadDanish() - { - // Backstage button text & key - this.backstageButtonText = "Filer"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimer båndet (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Vis kun fanenavnene på båndet."; - this.expandButtonScreenTipTitle = "Udvid båndet (Ctrl + F1)"; - this.expandButtonScreenTipText = "Vis båndet, så det altid er udvidet, selv når du klikker på en kommando."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Tilpas værktøjslinjen Hurtig adgang"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Flere kontrolelementer"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = " Tilpas værktøjslinjen Hurtig adgang"; - this.quickAccessToolBarMenuShowAbove = "Vis ovenover båndet"; - this.quickAccessToolBarMenuShowBelow = "Vis under båndet"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Føj til værktøjslinjen Hurtig adgang"; // Button - this.ribbonContextMenuAddGroup = "Føj til værktøjslinjen Hurtig adgang"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Tilføj Galleri til værktøjslinjen Hurtig adgang"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Føj til værktøjslinjen Hurtig adgang"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Fjern fra værktøjslinjen Hurtig adgang"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tilpas værktøjslinjen Hurtig adgang..."; - this.ribbonContextMenuShowBelow = "Vis værktøjslinjen Hurtig adgang under båndet"; - this.ribbonContextMenuShowAbove = "Vis værktøjslinjen Hurtig adgang ovenover båndet"; - this.ribbonContextMenuCustomizeRibbon = "Tilpas båndet..."; - this.ribbonContextMenuMinimizeRibbon = "Minimer båndet"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Denne kommando er aktuelt deaktiveret."; - } - - #endregion - - #region Portuguese - - private void LoadPortuguese() - { - // Backstage button text & key tip - this.backstageButtonText = "Ficheiro"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimizar o Friso (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Mostrar apenas os nomes dos separadores no Frisos."; - this.expandButtonScreenTipTitle = "Expandir o Friso (Ctrl + F1)"; - this.expandButtonScreenTipText = "Mostrar o Friso de modo a aparecer sempre expandido mesmo depois de clicar num comando."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personalizar Barra de Ferramentas de Acesso Rápido"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Mais Comandos..."; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personalizar Barra de Ferramentas de Acesso Rápido"; - this.quickAccessToolBarMenuShowAbove = "Mostrar Acima do Friso"; - this.quickAccessToolBarMenuShowBelow = "Mostrar Abaixo do Friso"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Adicionar à Barra de Ferramentas de Acesso Rápido"; - this.ribbonContextMenuAddGroup = "Adicionar Grupo à Barra de Ferramentas de Acesso Rápido"; - this.ribbonContextMenuAddGallery = "Adicionar Galeria à Barra de Ferramentas de Acesso Rápido"; - this.ribbonContextMenuAddMenu = "Adicionar Menu à Barra de Ferramentas de Acesso Rápido"; - this.ribbonContextMenuRemoveItem = "Remover da Barra de Ferramentas de Acesso Rápido"; - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizar Barra de Ferramentas de Acesso Rápido..."; - this.ribbonContextMenuShowBelow = "Mostrar Barra de Ferramentas de Acesso Rápido Abaixo do Friso"; - this.ribbonContextMenuShowAbove = "Mostrar Barra de Ferramentas de Acesso Rápido Acima do Friso"; - this.ribbonContextMenuCustomizeRibbon = "Personalizar o Friso..."; - this.ribbonContextMenuMinimizeRibbon = "Minimizar o Friso"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Este comando está desactivado actualmente."; - } - - #endregion - - #region Azerbaijani - - private void LoadAzerbaijani() - { - // Backstage button text & key tip - this.backstageButtonText = "Fayl"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Menyu lentini kiçilt (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Menyu lentini göstər və ya gizlət\n\nMenyu lentini kiçiləndə, yalnız tabların adları göstərilir"; - this.expandButtonScreenTipTitle = "Menyu lentini böyüt(Ctrl + F1)"; - this.expandButtonScreenTipText = " Menyu lentini göstər və ya gizlət\n\nMenyu lentini gizldəndə, yalnız, tabların adları göstərilir"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Sürətli Keçidin Alətlərini fərdiləşdir"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Digər nəzarət vasitələri"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = " Sürətli Keçidin Alətlərini fərdiləşdir "; - this.quickAccessToolBarMenuShowAbove = "Menyu lentinin üstündə göstər"; - this.quickAccessToolBarMenuShowBelow = " Menyu lentinin altında göstər "; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Sürətli Keçidin Alətlərinə əlavə et"; // Button - this.ribbonContextMenuAddGroup = " Sürətli Keçidin Alətlərinə Qrup əlavə et "; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = " Sürətli Keçidin Alətlərinə Qalereya əlavə et"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = " Sürətli Keçidin Alətlərinə Menyu əlavə et"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = " Sürətli Keçidin Alətlərindən sil"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = " Sürətli Keçidin Alətlərini fərdiləşdir..."; - this.ribbonContextMenuShowBelow = " Sürətli Keçidin Alətlərini Menyu lentinin altında göstər "; - this.ribbonContextMenuShowAbove = " Sürətli Keçidin Alətlərini Menyu lentinin üstündə göstər "; - this.ribbonContextMenuCustomizeRibbon = "Menyu lentini fərdiləşdir..."; - this.ribbonContextMenuMinimizeRibbon = " Menyu lentini kiçilt"; - } - - #endregion - - #region Finnish - - private void LoadFinnish() - { - this.backstageButtonText = "Tiedosto"; - this.backstageButtonKeyTip = "T"; - this.minimizeButtonScreenTipTitle = "Pienennä valintanauha (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Näytä valintanauhassa vain välilehtien nimet"; - this.expandButtonScreenTipTitle = "Laajenna valintanauha (Ctrl + F1)"; - this.expandButtonScreenTipText = "Näytä valintanauha aina laajennettuna silloinkin, kun valitset komennon"; - this.quickAccessToolBarDropDownButtonTooltip = "Mukauta pikatyökaluriviä"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Lisää valintoja"; - this.quickAccessToolBarMenuHeader = "Mukauta pikatyökaluriviä"; - this.quickAccessToolBarMenuShowAbove = "Näytä valintanauhan yläpuolella"; - this.quickAccessToolBarMenuShowBelow = "Näytä valintanauhan alapuolella"; - this.ribbonContextMenuAddItem = "Lisää pikatyökaluriville"; - this.ribbonContextMenuAddGroup = "Lisää ryhmä pikatyökaluriviin"; - this.ribbonContextMenuAddGallery = "Lisää valikoima pikatyökaluriviin"; - this.ribbonContextMenuAddMenu = "Lisää valikko pikatyökaluriviin"; - this.ribbonContextMenuRemoveItem = "Poista pikatyökaluriviltä"; - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Mukauta pikatyökaluriviä..."; - this.ribbonContextMenuShowBelow = "Näytä pikatyökalurivi valintanauhan alapuolella"; - this.ribbonContextMenuShowAbove = "Näytä pikatyökalurivi valintanauhan yläpuolella"; - this.ribbonContextMenuCustomizeRibbon = "Mukauta valintanauhaa..."; - this.ribbonContextMenuMinimizeRibbon = "Pienennä valintanauha"; - this.screenTipDisableReasonHeader = "Tämä komento on tällä hetkellä poissa käytöstä"; - } - - #endregion - - #region Norwegian - - private void LoadNorwegian() - { - // Backstage button text & key tip - this.backstageButtonText = "Fil"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimer båndet (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Viser bare kategorinavnene på båndet"; - this.expandButtonScreenTipTitle = "Utvider båndet (Ctrl + F1)"; - this.expandButtonScreenTipText = "Vis båndet slik at det alltid er utvidet selv etter at du har valgt en kommando"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Tilpass verktøylinje for hurtigtilgang"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Flere kontroller"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Tilpass verktøylinje for hurtigtilgang"; - this.quickAccessToolBarMenuShowAbove = "Vis over båndet"; - this.quickAccessToolBarMenuShowBelow = "Vis under båndet"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Legg til på verktøylinje for hurtigtilgang"; // Button - this.ribbonContextMenuAddGroup = "Legg til gruppe på verktøylinje for hurtigtilgang"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Legg til galleri på verktøylinje for hurtigtilgang"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Legg til meny på verktøylinje for hurtigtilgang"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Fjern verktøylinjen for hurtigtilgang"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tilpass verktøylinje for hurtigtilgang..."; - this.ribbonContextMenuShowBelow = "Vis verktøylinjen for hurtigtilgang under båndet"; - this.ribbonContextMenuShowAbove = "Vis verktøylinjen for hurtigtilgang over båndet"; - this.ribbonContextMenuCustomizeRibbon = "Tilpass båndet..."; - this.ribbonContextMenuMinimizeRibbon = "Minimer båndet"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Denne kommandoen er for øyeblikket deaktivert."; - } - - #endregion - - #region Turkish - - private void LoadTurkish() - { - // Backstage button text & key tip - this.backstageButtonText = "Dosya"; - this.backstageButtonKeyTip = "D"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Şeridi Daralt (Ctrl+F1)"; - this.minimizeButtonScreenTipText = "Daha fazla alana mı\nihtiyacınız var? Şeridi daraltın, yalnızca sekme isimleri görünsün."; - this.expandButtonScreenTipTitle = "Şeridi Sabitle (Ctrl+F1)"; - this.expandButtonScreenTipText = "Şeridi görmek mi istiyorsunuz? Çalışırken açık tutun."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Diğer denetimler"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; - this.quickAccessToolBarMenuShowAbove = "Şeridin Üstünde Göster"; - this.quickAccessToolBarMenuShowBelow = "Şeridin Altında Göster"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Hızlı Erişim Araç Çubuğu'na Ekle"; // Button - this.ribbonContextMenuAddGroup = "Grubu Hızlı Erişim Araç Çubuğu'na Ekle"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Galeriyi Hızlı Erişim Araç Çubuğu'na Ekle"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Menüyü Hızlı Erişim Araç Çubuğu'na Ekle"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Hızlı Erişim Araç Çubuğu'ndan Kaldır"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; - this.ribbonContextMenuShowBelow = "Hızlı Erişim Araç Çubuğu'nu Şeridin Altında Göster"; - this.ribbonContextMenuShowAbove = "Hızlı Erişim Araç Çubuğu'nu Şeridin Üstünde Göster"; - this.ribbonContextMenuCustomizeRibbon = "Şeridi Özelleştir..."; - this.ribbonContextMenuMinimizeRibbon = "Şeridi Daralt"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Bu komut şu anda devre dışı"; - this.screenTipF1LabelHeader = "Yardım için F1'e basın."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Durum Çubuğunu Özelleştir"; - } - - #endregion - - #region Hebrew - - private void LoadHebrew() - { - // Backstage button text & key tip - this.backstageButtonText = "קובץ"; - this.backstageButtonKeyTip = "ק"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "מזער את רצועת הכלים (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "הצג רק את שמות הכרטיסיות\nברצועת הכלים."; - this.expandButtonScreenTipTitle = "הרחב את רצועת הכלים (Ctrl + F1)"; - this.expandButtonScreenTipText = "הצג את רצועת הכלים כשהיא\nמורחבת תמיד, גם לאחר\nשתלחץ על הפקודה."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "התאמה אישית של סרגל הכלים לגישה מהירה"; - this.quickAccessToolBarMoreControlsButtonTooltip = "פקודות נוספות"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "התאמה אישית של סרגל הכלים לגישה מהירה"; - this.quickAccessToolBarMenuShowAbove = "הצג מעל לרצועת הכלים"; - this.quickAccessToolBarMenuShowBelow = "הצג מעל לרצועת הכלים"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "הוסף לסרגל הכלים לגישה מהירה"; // Button - this.ribbonContextMenuAddGroup = "הוסף קבוצה לסרגל הכלים לגישה מהירה"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "הוסף גלריה לסרגל הכלים לגישה מהירה"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "הוסף תפריט לסרגל הכלים לגישה מהירה"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "הסר מסרגל הכלים לגישה מהירה"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "של סרגל הכלים רצועת הכלים..."; - this.ribbonContextMenuShowBelow = "הצג את סרגל הכלים לגישה מהירה מתחת לרצועת הכלים"; - this.ribbonContextMenuShowAbove = "הצג את סרגל הכלים לגישה מהירה מעל לרצועת הכלים"; - this.ribbonContextMenuCustomizeRibbon = "התאמה אישית של רצועת הכלים..."; - this.ribbonContextMenuMinimizeRibbon = "מזער את רצועת הכלים"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "פקודה זו אינה זמינה כעת."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "התאמה אישית של שורת המצב"; - } - - #endregion - - #region Greek - - private void LoadGreek() - { - // Backstage button text & key tip - this.backstageButtonText = "Αρχείο"; - this.backstageButtonKeyTip = "Α"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Ελαχιστοποίηση της Κορδέλας (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Εμφάνιση μόνο των ονομάτων καρτελών στην Κορδέλα."; - this.expandButtonScreenTipTitle = "Ανάπτυξη της Κορδέλας (Ctrl + F1)"; - this.expandButtonScreenTipText = "Εμφάνιση της Κορδέλας προκειμένου να αναπτύσσεται πάντα, ακόμα και αφού κάνετε κλικ σε μια εντολή."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Περισσότερες εντολές"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης"; - this.quickAccessToolBarMenuShowAbove = "Εμφάνιση πάνω από την Κορδέλα"; - this.quickAccessToolBarMenuShowBelow = "Εμφάνιση κάτω από την Κορδέλα"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Προσθήκη στη γραμμή εργαλείων γρήγορης πρόσβασης"; // Button - this.ribbonContextMenuAddGroup = "Προσθήκη ομάδας στη γραμμή εργαλείων γρήγορης πρόσβασης"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Προσθήκη συλλογής στη γραμμή εργαλείων γρήγορης πρόσβασης"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Προσθήκη μενού στη γραμμή εργαλείων γρήγορης πρόσβασης"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Κατάργηση από τη γραμμή εργαλείων γρήγορης πρόσβασης"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης..."; - this.ribbonContextMenuShowBelow = "Εμφάνιση της γραμμής εργαλείων γρήγορης πρόσβασης κάτω από την Κορδέλα"; - this.ribbonContextMenuShowAbove = "Εμφάνιση της γραμμής εργαλείων γρήγορης πρόσβασης πάνω από την Κορδέλα"; - this.ribbonContextMenuCustomizeRibbon = "Προσαρμογή της Κορδέλας..."; - this.ribbonContextMenuMinimizeRibbon = "Ελαχιστοποίηση της Κορδέλας"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Αυτή η εντολή είναι απενεργοποιημένη προς το παρόν."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Προσαρμογή γραμμής κατάστασης"; - } - - #endregion - - #region Korean - - private void LoadKorean() - { - // Backstage button text & key tip - this.backstageButtonText = "파일"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "리본 메뉴를 최소화 합니다 (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "리본 메뉴를 표시하거나 숨깁니다\n\n리본 메뉴가 숨김 상태일때만,\n탭이름이 보여집니다"; - this.expandButtonScreenTipTitle = "리본 메뉴를 표시합니다 (Ctrl + F1)"; - this.expandButtonScreenTipText = "리본 메뉴를 표시하거나 숨깁니다\n\n리본 메뉴가 숨김 상태일때만,\n탭이름이 보여집니다"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "빠른 실행 도구 모음 사용자 지정"; - this.quickAccessToolBarMoreControlsButtonTooltip = "기타 컨트롤들"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "빠른 실행 도구 모음 사용자 지정"; - this.quickAccessToolBarMenuShowAbove = "리본 메뉴 위에 표시"; - this.quickAccessToolBarMenuShowBelow = "리본 메뉴 아래에 표시"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "빠른 실행 도구 모음에 추가"; // Button - this.ribbonContextMenuAddGroup = "그룹을 빠른 실행 도구 모음에 추가"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "갤러리를 빠른 실행 도구 모음에 추가"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "메뉴를 빠른 실행 도구 모음에 추가"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "빠른 실행 도구 모음에서 단추 제거"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "빠른 실행 도구 모음 사용자 지정..."; - this.ribbonContextMenuShowBelow = "리본 메뉴 아래에 빠른 실행 도구 모음 표시"; - this.ribbonContextMenuShowAbove = "리본 메뉴 위에 빠른 실행 도구 모음 표시"; - this.ribbonContextMenuCustomizeRibbon = "리본 메뉴 사용자 지정..."; - this.ribbonContextMenuMinimizeRibbon = "리본 메뉴 최소화"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "이 명령은 현재 사용할 수 없습니다."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "상태 표시줄 사용자 지정"; - } - - #endregion - - #region Lithuanian - - private void LoadLithuanian() - { - // Backstage button text & key tip - this.backstageButtonText = "Failas"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimizuoti juostelę (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Juostelėje rodyti tik skirtukų pavadinimus."; - this.expandButtonScreenTipTitle = "Išplėsti juostelę (Ctrl + F1)"; - this.expandButtonScreenTipText = "Rodyti juostelę taip, kad visada butų išskleista net ir spustelėjus komandą."; - - // QAT tooltips and menu items - - this.quickAccessToolBarDropDownButtonTooltip = "Tinkinti sparčiosios prieigos įrankių juostą"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Daugiau valdiklių"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Tinkinti sparčiosios prieigos įrankių juostą"; - this.quickAccessToolBarMenuShowAbove = "Rodyti virš juostelės"; - this.quickAccessToolBarMenuShowBelow = "Rodyti po juostele"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Pridėti į sparčiosios prieigos įrankių juostą"; // Button - this.ribbonContextMenuAddGroup = "Pridėti į sparčiosios prieigos įrankių juostą"; - this.ribbonContextMenuAddGallery = "Įtraukti galeriją į sparčiosios prieigos įrankių juostą"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Pridėti į sparčiosios prieigos įrankių juostą"; - this.ribbonContextMenuRemoveItem = "Šalinti iš sparčiosios prieigos įrankių juostos"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tinkinti sparčiosios prieigos įrankių juostą..."; - this.ribbonContextMenuShowBelow = "Rodyti po juostele"; - this.ribbonContextMenuShowAbove = "Rodyti virš juostelės"; - this.ribbonContextMenuCustomizeRibbon = "Tinkinti juostelę:"; - this.ribbonContextMenuMinimizeRibbon = "Minimizuoti juostelę"; - } - - #endregion - - #region Vietnamese - - private void LoadVietnamese() - { - // Backstage button text & key tip - this.backstageButtonText = "Tệp"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Thu gọn Ruy băng (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Hiện hoặc ẩn Ruy băng\n\nKhi Ruy băng ẩn, chỉ có tên thẻ được hiện"; - this.expandButtonScreenTipTitle = "Mở rộng Ruy băng (Ctrl + F1)"; - this.expandButtonScreenTipText = "Hiện hoặc ẩn Ruy băng\n\nKhi Ruy băng ẩn, chỉ có tên thẻ được hiện"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Tùy chỉnh thanh công cụ Truy cập nhanh"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Thêm điều khiển"; // khi có hai mũi tên ">>" - this.quickAccessToolBarMenuHeader = "Tùy chỉnh thanh công cụ Truy cập nhanh"; - this.quickAccessToolBarMenuShowAbove = "Hiện trên thanh Ruy băng"; - this.quickAccessToolBarMenuShowBelow = "Hiện dưới thanh Ruy băng"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Thêm vào thanh công cụ Truy cập nhanh"; // Button - this.ribbonContextMenuAddGroup = "Thêm nhóm vào thanh công cụ Truy cập nhanh"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Thêm bộ sưu tập vào thanh công cụ Truy cập nhanh"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Thêm menu vào thanh công cụ Truy cập nhanh"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Loại"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tùy chỉnh thanh công cụ Truy cập nhanh..."; - this.ribbonContextMenuShowBelow = "Hiện thanh công cụ truy cập nhanh dưới thanh Ruy băng"; - this.ribbonContextMenuShowAbove = "Hiện thanh công cụ truy cập nhanh trên thanh Ruy băng"; - this.ribbonContextMenuCustomizeRibbon = "Tùy biến thanh Ruy băng..."; - this.ribbonContextMenuMinimizeRibbon = "Thu gọn Ruy băng"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Lệnh này hiện bị tắt."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Tùy biến thanh Trạng thái"; - } - - #endregion - - #region Sinhala (Sri Lanka) - - private void LoadSinhala() - { - // Backstage button text & key tip - this.backstageButtonText = "ගොනුව"; - this.backstageButtonKeyTip = "න1"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "රිබනය හකුළන්න (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "රිබනය මත පටිති නාම පමණක් පෙන්වන්න."; - this.expandButtonScreenTipTitle = "රිබනය විහිදන්න (Ctrl + F1)"; - this.expandButtonScreenTipText = "රිබනය පෙන්වන්න, එවිට ඔබ\n\n විධානයක් ක්ලික් කළද එය\n\n සැමවිටම විහිදී පවතී."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය"; - this.quickAccessToolBarMoreControlsButtonTooltip = "තවත් විධාන"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය"; - this.quickAccessToolBarMenuShowAbove = "රිබනයට ඉහලින් පෙන්වන්න"; - this.quickAccessToolBarMenuShowBelow = "රිබනයට පහලින් පෙන්වන්න"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට එක් කරන්න"; // Button - this.ribbonContextMenuAddGroup = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට එක් කරන්න"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට ගැලරිය එක් කරන්න"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට මෙනුව එක් කරන්න"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයෙන් ඉවත් කරන්න"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය කරන්න..."; - this.ribbonContextMenuShowBelow = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය රිබනයට පහලින් පෙන්වන්න"; - this.ribbonContextMenuShowAbove = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය රිබනයට ඉහලින් පෙන්වන්න"; - this.ribbonContextMenuCustomizeRibbon = "රිබනය අභිමත කරණය කරන්න..."; - this.ribbonContextMenuMinimizeRibbon = "රිබනය හකුළන්න"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "මෙම විධානය දැනට භාවිතා කළ නොහැක"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "තත්ව තීරුව අභිමත කරණය"; - } - - #endregion - - #region Slovenian - - private void LoadSlovenian() - { - // Backstage button text & key tip - this.backstageButtonText = "Datoteka"; - this.backstageButtonKeyTip = "D"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Minimiraj trak (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Pokaži ali skrij trak\n\nKo je trak skrit, so prikazani samo zavihki"; - this.expandButtonScreenTipTitle = "Razširi trak (Ctrl + F1)"; - this.expandButtonScreenTipText = "Pokaži ali skrij trak\n\nKo je trak skrit, so prikazani samo zavihki"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Prilagodi orodno vrstico za hitri dostop"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Več ukazov"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Prilagodi orodno vrstico za hitri dostop"; - this.quickAccessToolBarMenuShowAbove = "Pokaži nad trakom"; - this.quickAccessToolBarMenuShowBelow = "Pokaži pod trakom"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Dodaj v orodno vrstico za hitri dostop"; // Button - this.ribbonContextMenuAddGroup = "Dodaj skupino orodni vrstici za hitri dostop"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Dodaj galerijo orodni vrstici za hitri dostop"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Dodaj meni orodni vrstici za hitri dostop"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Odstrani iz orodne vrstice za hitri dostop"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Prilagodi orodno vrstico za hitri dostop..."; - this.ribbonContextMenuShowBelow = "Pokaži orodno vrstico za hitri dostop pod trakom"; - this.ribbonContextMenuShowAbove = "Pokaži orodno vrstico za hitri dostop nad trakom"; - this.ribbonContextMenuCustomizeRibbon = "Prilagodi trak..."; - this.ribbonContextMenuMinimizeRibbon = "Minimiraj trak"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "Ta ukaz je trenutno onemogočen."; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Prilagodi vrstico stanja"; - } - - #endregion - - #region Catalan - - private void LoadCatalan() - { - // Backstage button text & key tip - this.backstageButtonText = "Fitxer"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - // TRANSLATOR'S NOTE: This block is not shown at Windows 7's Apps (WordPad or Paint) - this.minimizeButtonScreenTipTitle = "Minimitza la cinta (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "Ensenya o amaga la cinta\n\nQuan la cinta no es mostri, només s'ensenyen els noms de les pestanyes"; - this.expandButtonScreenTipTitle = "Expandeix la cinta (Ctrl + F1)"; - this.expandButtonScreenTipText = "Ensenya o amaga la cinta\n\nQuan la cinta no es mostri, només s'ensenyen els noms de les pestanyes"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Personalitza la barra d'eines d'accés ràpid"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Més controls"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Personalitza la barra d'eines d'accés ràpid"; - this.quickAccessToolBarMenuShowAbove = "Mostra sobre la cinta"; - this.quickAccessToolBarMenuShowBelow = "Mostra sota la cinta"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Afegeix a la barra d'eines d'accés ràpid"; // Button - this.ribbonContextMenuAddGroup = "Afegeix grup a la barra d'eines d'accés ràpid"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Afegeix galeria a la barra d'eines d'accés ràpid"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Afegeix menú a la barra d'eines d'accés ràpid"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Elimina la barra d'eines d'accés ràpid"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalitza la barra d'eines d'accés ràpid..."; - this.ribbonContextMenuShowBelow = "Mostra la barra d'eines d'accés ràpid sota la cinta"; - this.ribbonContextMenuShowAbove = "Mostra la barra d'eines d'accés ràpid sobre la cinta"; - this.ribbonContextMenuCustomizeRibbon = "Personalitza la cinta..."; - this.ribbonContextMenuMinimizeRibbon = "Minimitza la cinta"; - } - - #endregion - - #region Estonian - - private void LoadEstonian() - { - // Backstage button text & key tip - this.backstageButtonText = "Fail"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "Ahenda menüülint (Ctrl+F1)"; - this.minimizeButtonScreenTipText = "Kas vajate rohkem ruumi? Ahendage lint, siis kuvatakse \nainult menüünimed."; - this.expandButtonScreenTipTitle = "Kinnita lint (Ctrl+F1)"; - this.expandButtonScreenTipText = "Kas soovite, et lint oleks kuvatud? Saate selle töötamise \najal avatuna hoida."; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "Kohanda kiirpääsuriba"; - this.quickAccessToolBarMoreControlsButtonTooltip = "Rohkem juhtelemente"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "Kohanda kiirpääsuriba"; - this.quickAccessToolBarMenuShowAbove = "Kuva lindi kohal"; - this.quickAccessToolBarMenuShowBelow = "Kuva lindi all"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "Lisa kiirpääsuribale"; // Button - this.ribbonContextMenuAddGroup = "Lisa rühm kiirpääsuribale"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "Lisa galerii kiirpääsuribale"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "Lisa menüü kiirpääsuribale"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "Eemalda kiirpääsuribalt"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "Kohanda kiirpääsuriba..."; - this.ribbonContextMenuShowBelow = "Kuva kiirpääsuriba lindi all"; - this.ribbonContextMenuShowAbove = "Kuva kiirpääsuriba lindi kohal"; - this.ribbonContextMenuCustomizeRibbon = "Kohanda linti..."; - this.ribbonContextMenuMinimizeRibbon = "Ahenda menüülint"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - //Screentips - this.screenTipDisableReasonHeader = "See käsk on praegu keelatud."; - this.screenTipF1LabelHeader = "Spikri kuvamiseks vajutage klahvi F1"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "Kohanda olekuriba"; - } - - #endregion - - //Add by gamegear.tw - //Note: Adding Tradchinese - #region TradChinese - private void LoadTradChinese() - { - // Backstage button text & key tip - this.backstageButtonText = "檔案"; - this.backstageButtonKeyTip = "F"; - - // See right-top corner... (two different tooltips must be if you press it) - this.minimizeButtonScreenTipTitle = "功能區最小化 (Ctrl + F1)"; - this.minimizeButtonScreenTipText = "僅顯示功能區上的選項名稱,點擊選項後可顯示命令。"; - this.expandButtonScreenTipTitle = "展開功能區 (Ctrl + F1)"; - this.expandButtonScreenTipText = "始終顯示功能區選項及命令。"; - - // QAT tooltips and menu items - this.quickAccessToolBarDropDownButtonTooltip = "自訂快速存取工具列"; - this.quickAccessToolBarMoreControlsButtonTooltip = "其他命令"; // When two arrows appear ">>" - this.quickAccessToolBarMenuHeader = "自訂快速存取工具列"; - this.quickAccessToolBarMenuShowAbove = "在功能區上方顯示"; - this.quickAccessToolBarMenuShowBelow = "在功能區下方顯示"; - - // Click on Ribbon to show context menu - this.ribbonContextMenuAddItem = "新增到快速存取工具列"; // Button - this.ribbonContextMenuAddGroup = "將群組新增到快速存取工具列"; // For ex., by collapsed group - this.ribbonContextMenuAddGallery = "將樣式新增到快速存取工具列"; // For ex., by opened font context menu - this.ribbonContextMenuAddMenu = "將選單新增到快速存取工具列"; // By dashed splitter in context menu - this.ribbonContextMenuRemoveItem = "將選單從快速存取工具列中移除"; // By item in QAT - this.ribbonContextMenuCustomizeQuickAccessToolbar = "自訂快速存取工具列..."; - this.ribbonContextMenuShowBelow = "在功能表下方顯示快速存取工具列"; - this.ribbonContextMenuShowAbove = "在功能表上方顯示快速存取工具列"; - this.ribbonContextMenuCustomizeRibbon = "自訂功能區..."; - this.ribbonContextMenuMinimizeRibbon = "功能區最小化"; - - // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot - // (This prop was introduced after v1.3) - this.screenTipDisableReasonHeader = "命令已被禁用。"; - - // Right-click on status bar to see it. NEW! from v2.0 - this.customizeStatusBar = "自訂狀態工具列"; - } - #endregion - - - } -} +using System.ComponentModel; +using System.Globalization; + +namespace Fluent +{ + /// + /// Contains localizable Ribbon's properties. + /// Set Culture property to change current Ribbon localization or + /// set properties independently to use your localization + /// + public class RibbonLocalization : INotifyPropertyChanged + { + #region Implementation of INotifyPropertyChanged + + /// + /// Occurs then property is changed + /// + public event PropertyChangedEventHandler PropertyChanged; + + // Raises PropertYChanegd event + private void RaisePropertyChanged(string propertyName) + { + if (this.PropertyChanged != null) + this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region Culture + + private CultureInfo culture; + + /// + /// Gets or sets current culture used for localization + /// + public CultureInfo Culture + { + get { return this.culture; } + set + { + if (!Equals(this.culture, value)) + { + this.culture = value; + this.LoadCulture(this.culture); + this.RaisePropertyChanged("Culture"); + } + } + } + + #endregion + + #region Text of backstage button + + // Text of backstage button + private string backstageButtonText; + + /// + /// Gets or sets text of backstage button + /// + public string BackstageButtonText + { + get { return this.backstageButtonText; } + set + { + if (this.backstageButtonText != value) + { + this.backstageButtonText = value; + this.RaisePropertyChanged("BackstageButtonText"); + } + } + } + + #endregion + + #region KeyTip of backstage button + + // KeyTip of backstage button + private string backstageButtonKeyTip; + + /// + /// Gets or sets KeyTip of backstage button + /// + public string BackstageButtonKeyTip + { + get { return this.backstageButtonKeyTip; } + set + { + if (this.backstageButtonKeyTip != value) + { + this.backstageButtonKeyTip = value; + this.RaisePropertyChanged("BackstageButtonKeyTip"); + } + } + } + + #endregion + + #region Minimize Button ScreenTip Title + + // Minimize Button ScreenTip Title + private string minimizeButtonScreenTipTitle; + + /// + /// Minimize Button ScreenTip Title + /// + public string MinimizeButtonScreenTipTitle + { + get { return this.minimizeButtonScreenTipTitle; } + set + { + if (this.minimizeButtonScreenTipTitle != value) + { + this.minimizeButtonScreenTipTitle = value; + this.RaisePropertyChanged("MinimizeButtonScreenTipTitle"); + } + } + } + + #endregion + + #region Minimize Button ScreenTip Text + + // Minimize Button ScreenTip Text + private string minimizeButtonScreenTipText; + + /// + /// Minimize Button ScreenTip Text + /// + public string MinimizeButtonScreenTipText + { + get { return this.minimizeButtonScreenTipText; } + set + { + if (this.minimizeButtonScreenTipText != value) + { + this.minimizeButtonScreenTipText = value; + this.RaisePropertyChanged("MinimizeButtonScreenTipText"); + } + } + } + + #endregion + + #region Expand Button ScreenTip Title + + // Expand Button ScreenTip Title + private string expandButtonScreenTipTitle; + + /// + /// Expand Button ScreenTip Title + /// + public string ExpandButtonScreenTipTitle + { + get { return this.expandButtonScreenTipTitle; } + set + { + if (this.expandButtonScreenTipTitle != value) + { + this.expandButtonScreenTipTitle = value; + this.RaisePropertyChanged("ExpandButtonScreenTipTitle"); + } + } + } + + #endregion + + #region Expand Button ScreenTip Text + + // Expand Button ScreenTip Text + private string expandButtonScreenTipText; + + /// + /// Expand Button ScreenTip Text + /// + public string ExpandButtonScreenTipText + { + get { return this.expandButtonScreenTipText; } + set + { + if (this.expandButtonScreenTipText != value) + { + this.expandButtonScreenTipText = value; + this.RaisePropertyChanged("ExpandButtonScreenTipText"); + } + } + } + + #endregion + + #region Quick Access ToolBar DropDown Button ToolTip + + // Quick Access ToolBar DropDown Button ToolTip + private string quickAccessToolBarDropDownButtonTooltip; + + /// + /// Quick Access ToolBar DropDown Button ToolTip + /// + public string QuickAccessToolBarDropDownButtonTooltip + { + get { return this.quickAccessToolBarDropDownButtonTooltip; } + set + { + if (this.quickAccessToolBarDropDownButtonTooltip != value) + { + this.quickAccessToolBarDropDownButtonTooltip = value; + this.RaisePropertyChanged("QuickAccessToolBarDropDownButtonTooltip"); + } + } + } + + #endregion + + #region Quick Access ToolBar MoreControls Button ToolTip + + // Quick Access ToolBar MoreControls Button ToolTip + private string quickAccessToolBarMoreControlsButtonTooltip; + + /// + /// Quick Access ToolBar MoreControls Button ToolTip + /// + public string QuickAccessToolBarMoreControlsButtonTooltip + { + get { return this.quickAccessToolBarMoreControlsButtonTooltip; } + set + { + if (this.quickAccessToolBarMoreControlsButtonTooltip != value) + { + this.quickAccessToolBarMoreControlsButtonTooltip = value; + this.RaisePropertyChanged("QuickAccessToolBarMoreControlsButtonTooltip"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Header + + // Quick Access ToolBar Menu Header + private string quickAccessToolBarMenuHeader; + + /// + /// Quick Access ToolBar Menu Header + /// + public string QuickAccessToolBarMenuHeader + { + get { return this.quickAccessToolBarMenuHeader; } + set + { + if (this.quickAccessToolBarMenuHeader != value) + { + this.quickAccessToolBarMenuHeader = value; + this.RaisePropertyChanged("QuickAccessToolBarMenuHeader"); + } + } + } + + #endregion + + #region Quick Access ToolBar Context Menu Show Below + + // Quick Access ToolBar Minimize Quick Access Toolbar + private string quickAccessToolBarMenuShowBelow; + + /// + /// Quick Access ToolBar Minimize Quick Access Toolbar + /// + public string QuickAccessToolBarMenuShowBelow + { + get { return this.quickAccessToolBarMenuShowBelow; } + set + { + if (this.quickAccessToolBarMenuShowBelow != value) + { + this.quickAccessToolBarMenuShowBelow = value; + this.RaisePropertyChanged("QuickAccessToolBarMenuShowBelow"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Show Above + + // Quick Access ToolBar Menu Minimize Quick Access Toolbar + private string quickAccessToolBarMenuShowAbove; + + /// + /// Quick Access ToolBar Menu Minimize Quick Access Toolbar + /// + public string QuickAccessToolBarMenuShowAbove + { + get { return this.quickAccessToolBarMenuShowAbove; } + set + { + if (this.quickAccessToolBarMenuShowAbove != value) + { + this.quickAccessToolBarMenuShowAbove = value; + this.RaisePropertyChanged("QuickAccessToolBarMenuShowAbove"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Add Item + + // Quick Access ToolBar Menu Add Item + private string ribbonContextMenuAddItem; + + /// + /// Quick Access ToolBar Menu Add Item + /// + public string RibbonContextMenuAddItem + { + get { return this.ribbonContextMenuAddItem; } + set + { + if (this.ribbonContextMenuAddItem != value) + { + this.ribbonContextMenuAddItem = value; + this.RaisePropertyChanged("RibbonContextMenuAddItem"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Add Group + + // Quick Access ToolBar Menu Add Group + private string ribbonContextMenuAddGroup; + + /// + /// Quick Access ToolBar Menu Add Group + /// + public string RibbonContextMenuAddGroup + { + get { return this.ribbonContextMenuAddGroup; } + set + { + if (this.ribbonContextMenuAddGroup != value) + { + this.ribbonContextMenuAddGroup = value; + this.RaisePropertyChanged("RibbonContextMenuAddGroup"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Add Gallery + + // Quick Access ToolBar Menu Add Gallery + private string ribbonContextMenuAddGallery; + + /// + /// Quick Access ToolBar Menu Add Gallery + /// + public string RibbonContextMenuAddGallery + { + get { return this.ribbonContextMenuAddGallery; } + set + { + if (this.ribbonContextMenuAddGallery != value) + { + this.ribbonContextMenuAddGallery = value; + this.RaisePropertyChanged("RibbonContextMenuAddGallery"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Add Menu + + // Quick Access ToolBar Menu Add Menu + private string ribbonContextMenuAddMenu; + + /// + /// Quick Access ToolBar Menu Add Menu + /// + public string RibbonContextMenuAddMenu + { + get { return this.ribbonContextMenuAddMenu; } + set + { + if (this.ribbonContextMenuAddMenu != value) + { + this.ribbonContextMenuAddMenu = value; + this.RaisePropertyChanged("RibbonContextMenuAddMenu"); + } + } + } + + #endregion + + #region Quick Access ToolBar Menu Remove Item + + // Quick Access ToolBar Menu Remove Item + private string ribbonContextMenuRemoveItem; + + /// + /// Quick Access ToolBar Menu Remove Item + /// + public string RibbonContextMenuRemoveItem + { + get { return this.ribbonContextMenuRemoveItem; } + set + { + if (this.ribbonContextMenuRemoveItem != value) + { + this.ribbonContextMenuRemoveItem = value; + this.RaisePropertyChanged("RibbonContextMenuRemoveItem"); + } + } + } + + #endregion + + #region Ribbon Context Menu Customize Quick Access Toolbar + + // Ribbon Context Menu Customize Quick Access Toolbar + private string ribbonContextMenuCustomizeQuickAccessToolbar; + + /// + /// Ribbon Context Menu Customize Quick Access Toolbar + /// + public string RibbonContextMenuCustomizeQuickAccessToolBar + { + get { return this.ribbonContextMenuCustomizeQuickAccessToolbar; } + set + { + if (this.ribbonContextMenuCustomizeQuickAccessToolbar != value) + { + this.ribbonContextMenuCustomizeQuickAccessToolbar = value; + this.RaisePropertyChanged("RibbonContextMenuCustomizeQuickAccessToolBar"); + } + } + } + + #endregion + + #region Ribbon Context Menu Customize Ribbon + + // Ribbon Context Menu Customize Quick Access Toolbar + private string ribbonContextMenuCustomizeRibbon; + + /// + /// Ribbon Context Menu Customize Quick Access Toolbar + /// + public string RibbonContextMenuCustomizeRibbon + { + get { return this.ribbonContextMenuCustomizeRibbon; } + set + { + if (this.ribbonContextMenuCustomizeRibbon != value) + { + this.ribbonContextMenuCustomizeRibbon = value; + this.RaisePropertyChanged("RibbonContextMenuCustomizeRibbon"); + } + } + } + + #endregion + + #region Ribbon Context Menu Minimize Ribbon + + // Ribbon Context Menu Minimize Quick Access Toolbar + private string ribbonContextMenuMinimizeRibbon; + + /// + /// Ribbon Context Menu Minimize Quick Access Toolbar + /// + public string RibbonContextMenuMinimizeRibbon + { + get { return this.ribbonContextMenuMinimizeRibbon; } + set + { + if (this.ribbonContextMenuMinimizeRibbon != value) + { + this.ribbonContextMenuMinimizeRibbon = value; + this.RaisePropertyChanged("RibbonContextMenuMinimizeRibbon"); + } + } + } + + #endregion + + #region Ribbon Context Menu Show Below + + // Ribbon Context Menu Minimize Quick Access Toolbar + private string ribbonContextMenuShowBelow; + + /// + /// Ribbon Context Menu Minimize Quick Access Toolbar + /// + public string RibbonContextMenuShowBelow + { + get { return this.ribbonContextMenuShowBelow; } + set + { + if (this.ribbonContextMenuShowBelow != value) + { + this.ribbonContextMenuShowBelow = value; + this.RaisePropertyChanged("RibbonContextMenuShowBelow"); + } + } + } + + #endregion + + #region Ribbon Context Menu Show Above + + // Ribbon Context Menu Minimize Quick Access Toolbar + private string ribbonContextMenuShowAbove; + + /// + /// Ribbon Context Menu Minimize Quick Access Toolbar + /// + public string RibbonContextMenuShowAbove + { + get { return this.ribbonContextMenuShowAbove; } + set + { + if (this.ribbonContextMenuShowAbove != value) + { + this.ribbonContextMenuShowAbove = value; + this.RaisePropertyChanged("RibbonContextMenuShowAbove"); + } + } + } + + #endregion + + #region ScreenTipDisableReasonHeader + + // ScreenTip's Disable Reason Header + private string screenTipDisableReasonHeader; + + /// + /// Gets or sets ScreenTip's disable reason header + /// + public string ScreenTipDisableReasonHeader + { + get { return this.screenTipDisableReasonHeader; } + set + { + if (this.screenTipDisableReasonHeader != value) + { + this.screenTipDisableReasonHeader = value; + this.RaisePropertyChanged("ScreenTipDisableReasonHeader"); + } + } + } + + #endregion + + #region ScreenTipF1Label + + // ScreenTip's Disable Reason Header + private string screenTipF1LabelHeader; + + /// + /// Gets or sets ScreenTip's disable reason header + /// + public string ScreenTipF1LabelHeader + { + get { return this.screenTipF1LabelHeader; } + set + { + if (this.screenTipF1LabelHeader != value) + { + this.screenTipF1LabelHeader = value; + this.RaisePropertyChanged("ScreenTipF1LabelHeader"); + } + } + } + + #endregion + + #region Customize Status Bar + + // Text of backstage button + private string customizeStatusBar; + + /// + /// Gets or sets customize Status Bar + /// + public string CustomizeStatusBar + { + get { return this.customizeStatusBar; } + set + { + if (this.customizeStatusBar != value) + { + this.customizeStatusBar = value; + this.RaisePropertyChanged("CustomizeStatusBar"); + } + } + } + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public RibbonLocalization() + { + // Fallback values + this.LoadEnglish(); + + this.Culture = CultureInfo.CurrentUICulture; + } + + #endregion + + #region Methods + + // Coerce all localized values + private void LoadCulture(CultureInfo culture) + { + var language = culture.TwoLetterISOLanguageName; + + switch (language) + { + case "en": + this.LoadEnglish(); + break; + + case "ru": + this.LoadRussian(); + break; + + case "uk": + this.LoadUkrainian(); + break; + + case "fa": + this.LoadPersian(); + break; + + case "de": + this.LoadGerman(); + break; + + case "hu": + this.LoadHungarian(); + break; + + case "cs": + this.LoadCzech(); + break; + + case "fr": + this.LoadFrench(); + break; + + case "pl": + this.LoadPolish(); + break; + + case "ja": + this.LoadJapanese(); + break; + + case "nl": + this.LoadDutch(); + break; + case "pt": + { + if (culture.Name == "pt-BR") + { + this.LoadPortugueseBrazilian(); + } + else + { + this.LoadPortuguese(); + } + break; + } + + case "es": + this.LoadSpanish(); + break; + + //edit by gamegear.tw + //note: add TradChinese + case "zh": + if(culture.Name=="zh-tw") + { + this.LoadTradChinese(); + }else + { + this.LoadChinese(); + } + + break; + + case "sv": + this.LoadSwedish(); + break; + + case "sk": + this.LoadSlovak(); + break; + + case "ro": + this.LoadRomanian(); + break; + + case "it": + this.LoadItalian(); + break; + + case "ar": + this.LoadArabic(); + break; + + case "da": + this.LoadDanish(); + break; + + case "az": + this.LoadAzerbaijani(); + break; + + case "fi": + this.LoadFinnish(); + break; + + case "nb": + case "nn": + case "no": + this.LoadNorwegian(); + break; + + case "tr": + this.LoadTurkish(); + break; + + case "he": + this.LoadHebrew(); + break; + + case "ge": + this.LoadGreek(); + break; + + case "ko": + this.LoadKorean(); + break; + + case "lt": + this.LoadLithuanian(); + break; + + case "vi": + this.LoadVietnamese(); + break; + + case "si": + this.LoadSinhala(); + break; + + case "sl": + this.LoadSlovenian(); + break; + + case "ca": + this.LoadCatalan(); + break; + + case "et": + this.LoadEstonian(); + break; + } + + // Coerce all values + + this.RaisePropertyChanged("BackstageButtonText"); + this.RaisePropertyChanged("BackstageButtonKeyTip"); + + this.RaisePropertyChanged("MinimizeButtonScreenTipTitle"); + this.RaisePropertyChanged("MinimizeButtonScreenTipText"); + this.RaisePropertyChanged("ExpandButtonScreenTipTitle"); + this.RaisePropertyChanged("ExpandButtonScreenTipText"); + this.RaisePropertyChanged("QuickAccessToolBarDropDownButtonTooltip"); + this.RaisePropertyChanged("QuickAccessToolBarMoreControlsButtonTooltip"); + this.RaisePropertyChanged("QuickAccessToolBarMenuHeader"); + this.RaisePropertyChanged("QuickAccessToolBarMenuShowAbove"); + this.RaisePropertyChanged("QuickAccessToolBarMenuShowBelow"); + + this.RaisePropertyChanged("RibbonContextMenuAddItem"); + this.RaisePropertyChanged("RibbonContextMenuAddGroup"); + this.RaisePropertyChanged("RibbonContextMenuAddGallery"); + this.RaisePropertyChanged("RibbonContextMenuAddMenu"); + this.RaisePropertyChanged("RibbonContextMenuRemoveItem"); + this.RaisePropertyChanged("RibbonContextMenuCustomizeRibbon"); + this.RaisePropertyChanged("RibbonContextMenuCustomizeQuickAccessToolBar"); + this.RaisePropertyChanged("RibbonContextMenuShowAbove"); + this.RaisePropertyChanged("RibbonContextMenuShowBelow"); + this.RaisePropertyChanged("RibbonContextMenuMinimizeRibbon"); + + this.RaisePropertyChanged("ScreenTipDisableReasonHeader"); + this.RaisePropertyChanged("ScreenTipF1LabelHeader"); + this.RaisePropertyChanged("CustomizeStatusBar"); + } + + #endregion + + #region English + + private void LoadEnglish() + { + // Backstage button text & key tip + this.backstageButtonText = "File"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Collapse the Ribbon (Ctrl+F1)"; + this.minimizeButtonScreenTipText = "Need a bit more space? Collapse the ribbon so only the tab names show."; + this.expandButtonScreenTipTitle = "Pin the Ribbon (Ctrl+F1)"; + this.expandButtonScreenTipText = "Like seeing the ribbon? Keep it open while you work."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Customize Quick Access Toolbar"; + this.quickAccessToolBarMoreControlsButtonTooltip = "More controls"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Customize Quick Access Toolbar"; + this.quickAccessToolBarMenuShowAbove = "Show Above the Ribbon"; + this.quickAccessToolBarMenuShowBelow = "Show Below the Ribbon"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Add to Quick Access Toolbar"; // Button + this.ribbonContextMenuAddGroup = "Add Group to Quick Access Toolbar"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Add Gallery to Quick Access Toolbar"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Add Menu to Quick Access Toolbar"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Remove from Quick Access Toolbar"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customize Quick Access Toolbar..."; + this.ribbonContextMenuShowBelow = "Show Quick Access Toolbar Below the Ribbon"; + this.ribbonContextMenuShowAbove = "Show Quick Access Toolbar Above the Ribbon"; + this.ribbonContextMenuCustomizeRibbon = "Customize the Ribbon..."; + this.ribbonContextMenuMinimizeRibbon = "Collapse the Ribbon"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + //Screentips + this.screenTipDisableReasonHeader = "This command is currently disabled."; + this.screenTipF1LabelHeader = "Press F1 for help"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Customize Status Bar"; + } + + #endregion + + #region Russian + + private void LoadRussian() + { + this.backstageButtonText = "Файл"; + this.backstageButtonKeyTip = "Ф"; + + this.minimizeButtonScreenTipTitle = "Свернуть ленту (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Отображение или скрытие ленты\n\nКогда лента скрыта, отображаются только имена вкладок."; + this.expandButtonScreenTipTitle = "Развернуть ленту (Ctrl + F1)"; + this.expandButtonScreenTipText = "Отображение или скрытие ленты\n\nКогда лента скрыта, отображаются только имена вкладок."; + + this.quickAccessToolBarDropDownButtonTooltip = "Настройка панели быстрого доступа"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Другие элементы"; + this.quickAccessToolBarMenuHeader = "Настройка панели быстрого доступа"; + this.quickAccessToolBarMenuShowAbove = "Разместить над лентой"; + this.quickAccessToolBarMenuShowBelow = "Разместить под лентой"; + + this.ribbonContextMenuAddItem = "Добавить на панель быстрого доступа"; + this.ribbonContextMenuAddGroup = "Добавить группу на панель быстрого доступа"; + this.ribbonContextMenuAddGallery = "Добавить коллекцию на панель быстрого доступа"; + this.ribbonContextMenuAddMenu = "Добавить меню на панель быстрого доступа"; + this.ribbonContextMenuRemoveItem = "Удалить с панели быстрого доступа"; + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Настройка панели быстрого доступа..."; + this.ribbonContextMenuShowBelow = "Разместить панель быстрого доступа под лентой"; + this.ribbonContextMenuShowAbove = "Разместить панель быстрого доступа над лентой"; + this.ribbonContextMenuCustomizeRibbon = "Настройка ленты..."; + this.ribbonContextMenuMinimizeRibbon = "Свернуть ленту"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + this.screenTipDisableReasonHeader = "В настоящее время эта команда отключена."; + + this.customizeStatusBar = "Настройка строки состояния"; + } + + #endregion + + #region Ukrainian + + private void LoadUkrainian() + { + // Backstage button text & key tip + this.backstageButtonText = "Файл"; + this.backstageButtonKeyTip = "Ф"; + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Сховати Стрічку (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Показати або сховати Стрічку\n\nКоли стрічка схована, видно тільки назви вкладок"; + this.expandButtonScreenTipTitle = "Показати Стрічку (Ctrl + F1)"; + this.expandButtonScreenTipText = "Показати або сховати Стрічку\n\nКоли стрічка схована, видно тільки назви вкладок"; + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Налаштувати Панель Інструментів Швидкого Доступу"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Більше елементів"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Налаштувати Панель Інструментів Швидкого Доступу"; + this.quickAccessToolBarMenuShowAbove = "Показати Поверх Стрічки"; + this.quickAccessToolBarMenuShowBelow = "Показати Знизу Стрічки"; + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Додати до Панелі Інструментів Швидкого Доступу"; // Button + this.ribbonContextMenuAddGroup = "Додати Групу до Панелі Інструментів Швидкого Доступу"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Додати Галерею до Панелі Інструментів Швидкого Доступу"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Додати Меню до Панелі Інструментів Швидкого Доступу"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Видалити з Панелі Інструментів Швидкого Доступу"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Налаштувати Панель Інструментів Швидкого Доступу..."; + this.ribbonContextMenuShowBelow = "Показати Панель Інструментів Швидкого Доступу Знизу Стрічки"; + this.ribbonContextMenuShowAbove = "Показати Панель Інструментів Швидкого Доступу Поверх Стрічки"; + this.ribbonContextMenuCustomizeRibbon = "Налаштувати Стрічку..."; + this.ribbonContextMenuMinimizeRibbon = "Зменшити Стрічку"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Ця команда на даний момент недоступна."; + } + + #endregion + + #region Persian + + private void LoadPersian() + { + // Backstage button text & key tip + this.backstageButtonText = "فایل"; + this.backstageButtonKeyTip = "ف"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "کوچک کردن نوار (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "نمایش یا مخفی کردن نوار\n\nهنگامی که نوار مخفی است، تنها\nنام زبانه ها نمایش داده می شود."; + this.expandButtonScreenTipTitle = "بزرگ کردن نوار (Ctrl + F1)"; + this.expandButtonScreenTipText = "نمایش یا مخفی کردن نوار\n\nهنگامی که نوار مخفی است، تنها\nنام زبانه ها نمایش داده می شود."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "دلخواه سازی میله ابزار دسترسی سریع"; + this.quickAccessToolBarMoreControlsButtonTooltip = "ابزارهای دیگر"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "دلخواه سازی میله ابزار دسترسی سریع"; + this.quickAccessToolBarMenuShowAbove = "نمایش در بالای نوار"; + this.quickAccessToolBarMenuShowBelow = "نمایش در پایین نوار"; + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "اضافه کردن به میله ابزار دسترسی سریع"; // Button + this.ribbonContextMenuAddGroup = "اضافه کردن گروه به میله ابزار دسترسی سریع"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "اضافه کردن گالری به میله ابزار دسترسی سریع"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "اضاقه کردن منو به میله ابزار دسترسی سریع"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "حذف از میله ابزار دسترسی سریع"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "دلخواه سازی میله ابزار دسترسی سریع..."; + this.ribbonContextMenuShowBelow = "نمایش میله ابزار دسترسی سریع در پایین نوار"; + this.ribbonContextMenuShowAbove = "نمایش میله ابزار دسترسی سریع در بالای نوار"; + this.ribbonContextMenuCustomizeRibbon = "دلخواه سازی نوار..."; + this.ribbonContextMenuMinimizeRibbon = "کوچک کردن نوار"; + } + + #endregion + + #region German + + private void LoadGerman() + { + // Backstage button text & key tip + this.backstageButtonText = "Datei"; + this.backstageButtonKeyTip = "D"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Menüband minimieren (Strg+F1)"; + this.minimizeButtonScreenTipText = "Sie benötigen etwas mehr Platz? Reduzieren Sie das Menüband, sodass nur die Registerkartennamen angezeigt werden."; + this.expandButtonScreenTipTitle = "Menüband erweitern (Strg+F1)"; + this.expandButtonScreenTipText = "Ist es Ihnen lieber, wenn Sie das Menüband sehen? Lassen Sie es während der Arbeit geöffnet."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Symbolleiste für den Schnellzugriff anpassen"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Weitere Befehle…"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Symbolleiste für den Schnellzugriff anpassen"; + this.quickAccessToolBarMenuShowAbove = "Über dem Menüband anzeigen"; + this.quickAccessToolBarMenuShowBelow = "Unter dem Menüband anzeigen"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Zur Symbolleiste für den Schnellzugriff hinzufügen"; // Button + this.ribbonContextMenuAddGroup = "Gruppe zur Symbolleiste für den Schnellzugriff hinzufügen"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Katalog zur Symbolleiste für den Schnellzugriff hinzufügen"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Zur Symbolleiste für den Schnellzugriff hinzufügen"; // By dashed splitter in context menu + + this.ribbonContextMenuRemoveItem = "Aus Symbolleiste für den Schnellzugriff entfernen"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Symbolleiste für den Schnellzugriff anpassen..."; + this.ribbonContextMenuShowBelow = "Symbolleiste für den Schnellzugriff unter dem Menüband anzeigen"; + this.ribbonContextMenuShowAbove = "Symbolleiste für den Schnellzugriff über dem Menüband anzeigen"; + this.ribbonContextMenuCustomizeRibbon = "Menüband anpassen..."; + this.ribbonContextMenuMinimizeRibbon = "Menüband minimieren"; + + //Screentips + this.screenTipDisableReasonHeader = "Diese Funktion ist momentan deaktiviert."; + this.screenTipF1LabelHeader = "Drücken Sie F1 für die Hilfe"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Statusleiste anpassen"; + } + + #endregion + + #region Hungarian + + private void LoadHungarian() + { + // Backstage button text & key tip + this.backstageButtonText = "Fájl"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "A menüszalag összecsukása (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Csak a lapnevek megjelenítése a menüszalagon"; + this.expandButtonScreenTipTitle = "Menüszalag kibontása (Ctrl + F1)"; + this.expandButtonScreenTipText = "A menüszalag megjelenítése úgy, hogy egy parancsra kattintás után is látható maradjon"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Gyorselérési eszköztár testreszabása"; + this.quickAccessToolBarMoreControlsButtonTooltip = "További vezérlők"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Gyorselérési eszköztár testreszabása"; + this.quickAccessToolBarMenuShowAbove = "Megjelenítés a menüszalag alatt"; + this.quickAccessToolBarMenuShowBelow = "Megjelenítés a menüszalag felett"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Felvétel a gyorselérési eszköztárra"; // Button + this.ribbonContextMenuAddGroup = "Felvétel a gyorselérési eszköztárra"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Gyűjtemény felvétele a gyorselérési eszköztárra"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Felvétel a gyorselérési eszköztárra"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Eltávolítás a gyorselérési eszköztárról"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Gyorselérési eszköztár testreszabása..."; + this.ribbonContextMenuShowBelow = "A gyorselérési eszköztár megjelenítése a menüszalag alatt"; + this.ribbonContextMenuShowAbove = "A gyorselérési eszköztár megjelenítése a menüszalag felett"; + this.ribbonContextMenuCustomizeRibbon = "Menüszalag testreszabása..."; + this.ribbonContextMenuMinimizeRibbon = " A menüszalag összecsukása"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Ez a parancs jelenleg nem használható."; + } + + #endregion + + #region Czech + + private void LoadCzech() + { + // Backstage button text & key tip + this.backstageButtonText = "Soubor"; + this.backstageButtonKeyTip = "S"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Skrýt pás karet (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Zobrazit nebo skrýt pás karet\n\nJe-li pás karet skrytý, jsou zobrazeny pouze názvy karet"; + this.expandButtonScreenTipTitle = "Zobrazit pás karet (Ctrl + F1)"; + this.expandButtonScreenTipText = "Zobrazit nebo skrýt pás karet\n\nJe-li pás karet skrytý, jsou zobrazeny pouze názvy karet"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Přizpůsobit panel nástrojů Rychlý přístup"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Další příkazy"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Přizpůsobit panel nástrojů Rychlý přístup"; + this.quickAccessToolBarMenuShowAbove = "Zobrazit nad pásem karet"; + this.quickAccessToolBarMenuShowBelow = "Zobrazit pod pásem karet"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Přidat na panel nástrojů Rychlý přístup"; // Button + this.ribbonContextMenuAddGroup = "Přidat na panel nástrojů Rychlý přístup"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Přidat galerii na panel nástrojů Rychlý přístup"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Přidat na panel nástrojů Rychlý přístup"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Odebrat z panelu nástrojů Rychlý přístup"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Přizpůsobit panel nástrojů Rychlý přístup..."; + this.ribbonContextMenuShowBelow = "Zobrazit panel nástrojů Rychlý přístup pod pásem karet"; + this.ribbonContextMenuShowAbove = "Zobrazit panel nástrojů Rychlý přístup nad pásem karet"; + this.ribbonContextMenuCustomizeRibbon = "Přizpůsobit pás karet..."; + this.ribbonContextMenuMinimizeRibbon = "Skrýt pás karet"; + + //Screentips + this.screenTipDisableReasonHeader = "Tento příkaz je aktuálně zakázán."; + this.screenTipF1LabelHeader = "Stiskni F1 pro nápovědu"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Přizpůsobit Status Bar"; + } + + #endregion + + #region French + + private void LoadFrench() + { + // Backstage button text & key tip + this.backstageButtonText = "Fichier"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimiser le Ruban (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Afficher ou masquer le Ruban \n\nQuand le Ruban est masqué, seul les noms sont affichés"; + this.expandButtonScreenTipTitle = "Agrandir le Ruban (Ctrl + F1)"; + this.expandButtonScreenTipText = "Afficher ou masquer le Ruban \n\nQuand le Ruban est masqué, seul les noms sont affichés"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personnaliser la barre d'outils Accès Rapide"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Plus de contrôles"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personnaliser la barre d'outil Accès Rapide"; + this.quickAccessToolBarMenuShowAbove = "Afficher au dessus du Ruban"; + this.quickAccessToolBarMenuShowBelow = "Afficher en dessous du Ruban"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Ajouter un élément à la barre d'outils Accès Rapide"; // Button + this.ribbonContextMenuAddGroup = "Ajouter un groupe à la barre d'outils Accès Rapide"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Ajouter une galerie à la barre d'outils Accès Rapide"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Ajouter un menu à la barre d'outils Accès Rapide"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Supprimer de la barre d'outils Accès Rapide"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personnaliser la barre d'outils Accès Rapide..."; + this.ribbonContextMenuShowBelow = "Afficher la barre d'outils Accès Rapide en dessous du Ruban"; + this.ribbonContextMenuShowAbove = "Afficher la barre d'outils Accès Rapide au dessus du Ruban"; + this.ribbonContextMenuCustomizeRibbon = "Personnaliser le Ruban..."; + this.ribbonContextMenuMinimizeRibbon = "Minimiser le Ruban"; + this.customizeStatusBar = "Personnaliser la barre de statut"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + this.screenTipDisableReasonHeader = "Cette commande est actuellement désactivée."; + } + + #endregion + + #region Polish + + private void LoadPolish() + { + // Backstage button text & key tip + this.backstageButtonText = "Plik"; + this.backstageButtonKeyTip = "P"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimalizuj Wstążkę (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Pokazuje lub ukrywa Wstążkę\n\nGdy Wstążka jest ukryta, tylko nazwy zakładek są widoczne"; + this.expandButtonScreenTipTitle = "Rozwiń Wstążkę (Ctrl + F1)"; + this.expandButtonScreenTipText = "Pokazuje lub ukrywa Wstążkę\n\nGdy Wstążka jest ukryta, tylko nazwy zakładek są widoczne"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Dostosuj pasek narzędzi Szybki dostęp"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Więcej poleceń..."; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Dostosuj pasek narzędzi Szybki dostęp"; + this.quickAccessToolBarMenuShowAbove = "Pokaż powyżej Wstążki"; + this.quickAccessToolBarMenuShowBelow = "Pokaż poniżej Wstążki"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Dodaj do paska narzędzi Szybki dostęp"; // Button + this.ribbonContextMenuAddGroup = "Dodaj Grupę do paska narzędzi Szybki dostęp"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Dodaj Galerię do paska narzędzi Szybki dostęp"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Dodaj do paska narzędzi Szybki dostęp"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Usuń z paska narzędzi Szybki dostęp"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Dostosuj pasek narzędzi Szybki dostęp..."; + this.ribbonContextMenuShowBelow = "Pokaż pasek Szybki dostęp poniżej Wstążki"; + this.ribbonContextMenuShowAbove = "Pokaż pasek Szybki dostęp powyżej Wstążki"; + this.ribbonContextMenuCustomizeRibbon = "Dostosuj Wstążkę..."; + this.ribbonContextMenuMinimizeRibbon = "Minimalizuj Wstążkę"; + } + + #endregion + + #region Japanese + + private void LoadJapanese() + { + // Backstage button text & key tip + this.backstageButtonText = "ファイル"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "リボンの最小化 (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "リボンの表示/非表示を切り替えます。\n\nリボンを非表示にすると、タブ名のみが表示されます。"; + this.expandButtonScreenTipTitle = "リボンの展開 (Ctrl + F1)"; + this.expandButtonScreenTipText = "リボンの表示/非表示を切り替えます。\n\nリボンを非表示にすると、タブ名のみが表示されます。"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "クイック アクセス ツール バーのユーザー設定"; + this.quickAccessToolBarMoreControlsButtonTooltip = "その他のボタン"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "クイック アクセス ツール バーのユーザー設定"; + this.quickAccessToolBarMenuShowAbove = "リボンの上に表示"; + this.quickAccessToolBarMenuShowBelow = "リボンの下に表示"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "クイック アクセス ツール バーに追加"; // Button + this.ribbonContextMenuAddGroup = "グループをクイック アクセス ツール バーに追加"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "ギャラリーをクイック アクセス ツール バーに追加"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "メニューをクイック アクセス ツール バーに追加"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "クイック アクセス ツール バーから削除"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "クイック アクセス ツール バーのユーザー設定..."; + this.ribbonContextMenuShowBelow = "クイック アクセス ツール バーをリボンの下に表示"; + this.ribbonContextMenuShowAbove = "クイック アクセス ツール バーをリボンの上に表示"; + this.ribbonContextMenuCustomizeRibbon = "リボンのユーザー設定..."; + this.ribbonContextMenuMinimizeRibbon = "リボンの最小化"; + this.customizeStatusBar = "ステータス バーのユーザー設定"; + + this.screenTipDisableReasonHeader = "このコマンドは現在無効になっています"; + } + + #endregion + + #region Dutch + + private void LoadDutch() + { + // Backstage button text & key tip + this.backstageButtonText = "Bestand"; + this.backstageButtonKeyTip = "B"; + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Het lint minimaliseren (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Verberg of laat het lint zien\n\nWanneer het lint verborgen is, zijn alleen de tabulatie namen zichtbaar"; + this.expandButtonScreenTipTitle = "Het lint Maximaliseren (Ctrl + F1)"; + this.expandButtonScreenTipText = "Verberg of laat het lint zien\n\nWanneer het lint verborgen is, zijn alleen de tabulatie namen zichtbaar"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Werkbalk snelle toegang aanpassen"; + this.quickAccessToolBarMoreControlsButtonTooltip = "meer opdrachten"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = " Werkbalk snelle toegang aanpassen "; + this.quickAccessToolBarMenuShowAbove = "Boven het lint weergeven"; + this.quickAccessToolBarMenuShowBelow = "beneden het lint weergeven"; + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Menu toevoegen aan werkbalk snelle toegang"; // Button + this.ribbonContextMenuAddGroup = "Groep toevoegen aan werkbalk snelle toegang"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Galerij toevoegen aan werkbalk snelle toegang"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = " Menu toevoegen aan werkbalk snelle toegang "; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = " Verwijder uit werkbalk snelle toegang "; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customize Quick Access Toolbar..."; + this.ribbonContextMenuShowBelow = " Werkbalk snelle toegang onder het lint weergeven"; + this.ribbonContextMenuShowAbove = " Werkbalk snelle toegang boven het lint weergeven "; + this.ribbonContextMenuCustomizeRibbon = "Lint aanpassen..."; + this.ribbonContextMenuMinimizeRibbon = " Het lint minimaliseren"; + } + + #endregion + + #region Brazilian + + private void LoadPortugueseBrazilian() + { + // Backstage button text & key tip + this.backstageButtonText = "Arquivo"; + this.backstageButtonKeyTip = "A"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimizar o Ribbon (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Mostrar ou esconder o Ribbon\n\nQuando o Ribbon estiver escondido, somente o nome das abas serão mostrados"; + this.expandButtonScreenTipTitle = "Expandir o Ribbon (Ctrl + F1)"; + this.expandButtonScreenTipText = "Mostrar ou esconder o Ribbon\n\nQuando o Ribbon estiver escondido, somente o nome das abas serão mostrados"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Customizar Barra de acesso rápido"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Mais controles"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = " Customizar Barra de acesso rápido"; + this.quickAccessToolBarMenuShowAbove = "Mostrar acima do Ribbon"; + this.quickAccessToolBarMenuShowBelow = "Mostrar abaixo do Ribbon"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Adicionar para Barra de acesso rápido"; // Button + this.ribbonContextMenuAddGroup = " Adicionar o grupo para Barra de acesso rápido"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Adicionar a galeria para Barra de acesso rápido"; + // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = " Adicionar o menu para Barra de acesso rápido"; + // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Remover da Barra de acesso rápido"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Customizar Barra de acesso rápido..."; + this.ribbonContextMenuShowBelow = "Mostrar Barra de acesso rápido abaixo do Ribbon"; + this.ribbonContextMenuShowAbove = "Mostrar Barra de acesso rápido acima do Ribbon"; + this.ribbonContextMenuCustomizeRibbon = "Customizar o Ribbon..."; + this.ribbonContextMenuMinimizeRibbon = "Minimizar o Ribbon"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Este comando está desativado."; + } + + #endregion + + #region Spanish + + private void LoadSpanish() + { + // Backstage button text & key tip + this.backstageButtonText = "Archivo"; + this.backstageButtonKeyTip = "A"; + + // See right-top corner... (two different tooltips must be if you press it) + // TRANSLATOR'S NOTE: This block is not shown at Windows 7's Apps (WordPad or Paint) + this.minimizeButtonScreenTipTitle = "Minimizar la cinta (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Muestra u oculta la cinta\n\nCuando la cinta está oculta, sólo se muestran los nombres de las pestañas"; + this.expandButtonScreenTipTitle = "Expandir la cinta (Ctrl + F1)"; + this.expandButtonScreenTipText = "Muestra u oculta la cinta\n\nCuando la cinta está oculta, sólo se muestran los nombres de las pestañas"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personalizar barra de herramientas de acceso rápido"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Más controles"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personalizar barra de herramientas de acceso rápido"; + this.quickAccessToolBarMenuShowAbove = "Mostrar sobre la cinta"; + this.quickAccessToolBarMenuShowBelow = "Mostrar bajo la cinta"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Agregar a la barra de herramientas de acceso rápido"; // Button + this.ribbonContextMenuAddGroup = "Agregar grupo a la barra de herramientas de acceso rápido"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Agregar galería a la barra de herramientas de acceso rápido"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Agregar menú a la barra de herramientas de acceso rápido"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Quitar de la barra de herramientas de acceso rápido"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizar la barra de herramientas de acceso rápido..."; + this.ribbonContextMenuShowBelow = "Mostrar barra de herramientas de acceso rápido bajo la cinta"; + this.ribbonContextMenuShowAbove = "Mostrar barra de herramientas de acceso rápido sobre la cinta"; + this.ribbonContextMenuCustomizeRibbon = "Personalizar la cinta..."; + this.ribbonContextMenuMinimizeRibbon = "Minimizar la cinta"; + + //Screentips + this.screenTipDisableReasonHeader = "Este comando está desactivado actualmente"; + this.screenTipF1LabelHeader = "Pulse F1 para obtener más ayuda"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Personalizar barra de estado"; + } + + #endregion + + #region Chinese + + private void LoadChinese() + { + // Backstage button text & key tip + this.backstageButtonText = "文件"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "功能区最小化 (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "仅显示功能区上的选项卡名称。单击选项卡可显示命令。"; + this.expandButtonScreenTipTitle = "展开功能区 (Ctrl + F1)"; + this.expandButtonScreenTipText = "始终显示功能区选项卡和命令。"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "自定义快速访问具栏"; + this.quickAccessToolBarMoreControlsButtonTooltip = "其他命令"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "自定义快速访问工具栏"; + this.quickAccessToolBarMenuShowAbove = "在功能区上方显示"; + this.quickAccessToolBarMenuShowBelow = "在功能区下方显示"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "添加到快速访问工具栏"; // Button + this.ribbonContextMenuAddGroup = "在快速访问工具栏中添加组"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "在快速访问工具栏中添加样式"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "在快速访问工具栏中添加菜单"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "在快速访问工具栏中移除"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "自定义快速访问工具栏..."; + this.ribbonContextMenuShowBelow = "在功能区下方显示快速访问工具栏"; + this.ribbonContextMenuShowAbove = "在功能区上方显示快速访问工具栏"; + this.ribbonContextMenuCustomizeRibbon = "自定义功能区..."; + this.ribbonContextMenuMinimizeRibbon = "功能区最小化"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "此命令当前已被禁用。"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "自定义状态栏"; + } + + #endregion + + #region Swedish + + private void LoadSwedish() + { + // Backstage button text & key tip + this.backstageButtonText = "Arkiv"; + this.backstageButtonKeyTip = "A"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimera menyfliksområdet (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Visa eller göm menyfliksområdet \n\nNär menyfliksområdet är dolt, visas endast flikarna"; + this.expandButtonScreenTipTitle = "Expandera menyfliksområdet (Ctrl + F1)"; + this.expandButtonScreenTipText = "Visa eller göm menyfliksområdet \n\nNär menyfliksområdet är dolt, visas endast flikarna"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Anpassa verktygsfältet Snabbåtkomst "; + this.quickAccessToolBarMoreControlsButtonTooltip = "Fler kommandon"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = " Anpassa verktygsfältet Snabbåtkomst"; + this.quickAccessToolBarMenuShowAbove = "Visa ovanför menyfliksområdet"; + this.quickAccessToolBarMenuShowBelow = "Visa under menyfliksområdet"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Lägg till i verktygsfältet Snabbåtkomst"; // Button + this.ribbonContextMenuAddGroup = "Lägg till i verktygsfältet Snabbåtkomst"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Lägg till galleriet i verktygsfältet Snabbåtkomst"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = " Lägg till menyn i verktygsfältet Snabbåtkomst "; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Ta bort från verktygsfältet Snabbåtkomst"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Anpassa verktygsfältet Snabbåtkomst..."; + this.ribbonContextMenuShowBelow = " Visa verktygsfältet Snabbåtkomst under menyfliksområdet"; + this.ribbonContextMenuShowAbove = " Visa verktygsfältet Snabbåtkomst ovanför menyfliksområdet "; + this.ribbonContextMenuCustomizeRibbon = "Anpassa menyfliksområdet..."; + this.ribbonContextMenuMinimizeRibbon = "Minimera menyfliksområdet"; + } + + #endregion + + #region Slovak + + private void LoadSlovak() + { + // Backstage button text & key tip + this.backstageButtonText = "Súbor"; + this.backstageButtonKeyTip = "S"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Skryť pás s nástrojmi (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Zobraziť alebo skryť pás s nástrojmi\n\nKeď je pás s nástrojmi skrytý, sú zobrazené iba názvy kariet"; + this.expandButtonScreenTipTitle = "Zobraziť pás s nástrojmi (Ctrl + F1)"; + this.expandButtonScreenTipText = " Zobraziť alebo skryť pás s nástrojmi\n\nKeď je pás s nástrojmi skrytý, sú zobrazené iba názvy kariet "; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Prispôsobenie panela s nástrojmi Rýchly prístup"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Ďalšie príkazy"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Prispôsobenie panela s nástrojmi Rýchly prístup"; + this.quickAccessToolBarMenuShowAbove = " Zobraziť nad pásom s nástrojmi "; + this.quickAccessToolBarMenuShowBelow = "Zobraziť pod pásom s nástrojmi"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Pridať na panel s nástrojmi Rýchly prístup"; // Button + this.ribbonContextMenuAddGroup = " Pridať na panel s nástrojmi Rýchly prístup "; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = " Pridať galériu do panela s nástrojmi Rýchly prístup "; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Pridať na panel s nástrojmi Rýchly prístup"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Odstrániť z panela s nástrojmi Rýchly prístup "; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = " Prispôsobenie panela s nástrojmi Rýchly prístup..."; + this.ribbonContextMenuShowBelow = "Panel s nástrojmi Rýchly prístup zobraziť pod panelom s nástrojmi"; + this.ribbonContextMenuShowAbove = "Panel s nástrojmi Rýchly prístup zobraziť nad panelom s nástrojmi "; + this.ribbonContextMenuCustomizeRibbon = "Prispôsobenie panela s nástrojmi Rýchly prístup..."; + this.ribbonContextMenuMinimizeRibbon = "Minimalizovať pás s nástrojmi"; + } + + #endregion + + #region Romanian + + private void LoadRomanian() + { + // Backstage button text & key tip + this.backstageButtonText = "Fișier"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimizează Ribbon-ul (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Afișează sau ascunde Ribbon-ul\nCând Ribbon-ul este ascuns, sunt afișate doar numele taburilor"; + this.expandButtonScreenTipTitle = "Expandează Ribbon-ul (Ctrl + F1)"; + this.expandButtonScreenTipText = "Afișează sau ascunde Ribbon-ul\nCând Ribbon-ul este ascuns, sunt afișate doar numele taburilor"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personalizează Bara de Acces Rapid"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Mai multe controale"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personalizează Bara de Acces Rapid"; + this.quickAccessToolBarMenuShowAbove = "Afișează peste Ribbon"; + this.quickAccessToolBarMenuShowBelow = "Afișează sub Ribbon"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Adaugă la Bara de Acess Rapid"; // Button + this.ribbonContextMenuAddGroup = "Adaugă Grupul la Bara de Acess Rapid"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Adaugă Galeria la Bara de Acess Rapid"; + // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Adaugă Meniul la Bara de Acess Rapid"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Eimină din Bara de Acess Rapid"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizează Bara de Acces Rapid..."; + this.ribbonContextMenuShowBelow = "Afișează Bara de Acces Rapid sub Ribbon"; + this.ribbonContextMenuShowAbove = "Afișează Bara de Acces Rapid peste Ribbon"; + this.ribbonContextMenuCustomizeRibbon = "Personalizează Ribbon-ul..."; + this.ribbonContextMenuMinimizeRibbon = "Minimizează Ribbon-ul..."; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Această comandă nu este disponibilă momentan."; + } + + #endregion + + #region Italian + + private void LoadItalian() + { + // Backstage button text & key tip + this.backstageButtonText = "File"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Riduci a icona barra multifunzione (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Consente di visualizzare solo i nomi delle schede nella barra multifunzione."; + this.expandButtonScreenTipTitle = "Espandi la barra multifunzione (Ctrl + F1)"; + this.expandButtonScreenTipText = "Visualizza la barra multifunzione in modo che rimanga sempre espansa, anche se l’utente ha fatto click su un comando."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personalizza barra di accesso rapido"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Altri comandi…"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personalizza barra di accesso rapido"; + this.quickAccessToolBarMenuShowAbove = "Mostra sopra la barra multifunzione"; + this.quickAccessToolBarMenuShowBelow = "Mostra sotto la barra multifunzione"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Aggiungi alla barra di accesso rapido"; // Button + this.ribbonContextMenuAddGroup = "Aggiungi gruppo alla barra di accesso rapido"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Aggiungi raccolta alla barra di accesso rapido"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Aggiungi menu alla barra di accesso rapido"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Rimuovi dalla barra di accesso rapido"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizza barra di accesso rapido..."; + this.ribbonContextMenuShowBelow = "Mostra la barra di accesso rapido sotto la barra multifunzione"; + this.ribbonContextMenuShowAbove = "Mostra la barra di accesso rapido sopra la barra multifunzione"; + this.ribbonContextMenuCustomizeRibbon = "Personalizza barra multifunzione..."; + this.ribbonContextMenuMinimizeRibbon = "Riduci a icona barra multifunzione"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Questo commando è disattivato."; + } + + #endregion + + #region Arabic + + private void LoadArabic() + { + // Backstage button text & key tip + this.backstageButtonText = "ملف "; + this.backstageButtonKeyTip = "م "; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "(Ctrl + F1)تصغير الشريط "; + this.minimizeButtonScreenTipText = "إظهار أسماء علامات التبويب فقط على الشريط."; + this.expandButtonScreenTipTitle = "(Ctrl + F1)توسيع الشريط "; + this.expandButtonScreenTipText = "إظهار الشريط بحيث يكون موسعاً دائماً حتى بعد النقر فوق أمر."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "تخصيص شريط أدوات الوصول السريع"; + this.quickAccessToolBarMoreControlsButtonTooltip = "أوامر إضافية"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "تخصيص شريط أدوات الوصول السريع"; + this.quickAccessToolBarMenuShowAbove = "إظهار أعلى الشريط"; + this.quickAccessToolBarMenuShowBelow = "إظهار أسفل الشريط"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "إضافة إلى شريط أدوات الوصول السريع"; // Button + this.ribbonContextMenuAddGroup = "إضافة إلى شريط أدوات الوصول السريع"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "إضافة إلى شريط أدوات الوصول السريع"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "إضافة إلى شريط أدوات الوصول السريع"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "إزالة إلى شريط أدوات الوصول السريع"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "تخصيص شريط أدوات الوصول السريع..."; + this.ribbonContextMenuShowBelow = "إظهار شريط أدوات الوصول السريع أسفل الشريط"; + this.ribbonContextMenuShowAbove = "إظهار شريط أدوات الوصول السريع أعلى الشريط"; + this.ribbonContextMenuCustomizeRibbon = "تخصيص الشريط..."; + this.ribbonContextMenuMinimizeRibbon = "تصغير الشريط"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "تم حالياً تعطيل هذا الأمر."; + } + + #endregion + + #region Danish + + private void LoadDanish() + { + // Backstage button text & key + this.backstageButtonText = "Filer"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimer båndet (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Vis kun fanenavnene på båndet."; + this.expandButtonScreenTipTitle = "Udvid båndet (Ctrl + F1)"; + this.expandButtonScreenTipText = "Vis båndet, så det altid er udvidet, selv når du klikker på en kommando."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Tilpas værktøjslinjen Hurtig adgang"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Flere kontrolelementer"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = " Tilpas værktøjslinjen Hurtig adgang"; + this.quickAccessToolBarMenuShowAbove = "Vis ovenover båndet"; + this.quickAccessToolBarMenuShowBelow = "Vis under båndet"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Føj til værktøjslinjen Hurtig adgang"; // Button + this.ribbonContextMenuAddGroup = "Føj til værktøjslinjen Hurtig adgang"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Tilføj Galleri til værktøjslinjen Hurtig adgang"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Føj til værktøjslinjen Hurtig adgang"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Fjern fra værktøjslinjen Hurtig adgang"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tilpas værktøjslinjen Hurtig adgang..."; + this.ribbonContextMenuShowBelow = "Vis værktøjslinjen Hurtig adgang under båndet"; + this.ribbonContextMenuShowAbove = "Vis værktøjslinjen Hurtig adgang ovenover båndet"; + this.ribbonContextMenuCustomizeRibbon = "Tilpas båndet..."; + this.ribbonContextMenuMinimizeRibbon = "Minimer båndet"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Denne kommando er aktuelt deaktiveret."; + } + + #endregion + + #region Portuguese + + private void LoadPortuguese() + { + // Backstage button text & key tip + this.backstageButtonText = "Ficheiro"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimizar o Friso (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Mostrar apenas os nomes dos separadores no Frisos."; + this.expandButtonScreenTipTitle = "Expandir o Friso (Ctrl + F1)"; + this.expandButtonScreenTipText = "Mostrar o Friso de modo a aparecer sempre expandido mesmo depois de clicar num comando."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personalizar Barra de Ferramentas de Acesso Rápido"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Mais Comandos..."; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personalizar Barra de Ferramentas de Acesso Rápido"; + this.quickAccessToolBarMenuShowAbove = "Mostrar Acima do Friso"; + this.quickAccessToolBarMenuShowBelow = "Mostrar Abaixo do Friso"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Adicionar à Barra de Ferramentas de Acesso Rápido"; + this.ribbonContextMenuAddGroup = "Adicionar Grupo à Barra de Ferramentas de Acesso Rápido"; + this.ribbonContextMenuAddGallery = "Adicionar Galeria à Barra de Ferramentas de Acesso Rápido"; + this.ribbonContextMenuAddMenu = "Adicionar Menu à Barra de Ferramentas de Acesso Rápido"; + this.ribbonContextMenuRemoveItem = "Remover da Barra de Ferramentas de Acesso Rápido"; + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalizar Barra de Ferramentas de Acesso Rápido..."; + this.ribbonContextMenuShowBelow = "Mostrar Barra de Ferramentas de Acesso Rápido Abaixo do Friso"; + this.ribbonContextMenuShowAbove = "Mostrar Barra de Ferramentas de Acesso Rápido Acima do Friso"; + this.ribbonContextMenuCustomizeRibbon = "Personalizar o Friso..."; + this.ribbonContextMenuMinimizeRibbon = "Minimizar o Friso"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Este comando está desactivado actualmente."; + } + + #endregion + + #region Azerbaijani + + private void LoadAzerbaijani() + { + // Backstage button text & key tip + this.backstageButtonText = "Fayl"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Menyu lentini kiçilt (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Menyu lentini göstər və ya gizlət\n\nMenyu lentini kiçiləndə, yalnız tabların adları göstərilir"; + this.expandButtonScreenTipTitle = "Menyu lentini böyüt(Ctrl + F1)"; + this.expandButtonScreenTipText = " Menyu lentini göstər və ya gizlət\n\nMenyu lentini gizldəndə, yalnız, tabların adları göstərilir"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Sürətli Keçidin Alətlərini fərdiləşdir"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Digər nəzarət vasitələri"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = " Sürətli Keçidin Alətlərini fərdiləşdir "; + this.quickAccessToolBarMenuShowAbove = "Menyu lentinin üstündə göstər"; + this.quickAccessToolBarMenuShowBelow = " Menyu lentinin altında göstər "; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Sürətli Keçidin Alətlərinə əlavə et"; // Button + this.ribbonContextMenuAddGroup = " Sürətli Keçidin Alətlərinə Qrup əlavə et "; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = " Sürətli Keçidin Alətlərinə Qalereya əlavə et"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = " Sürətli Keçidin Alətlərinə Menyu əlavə et"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = " Sürətli Keçidin Alətlərindən sil"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = " Sürətli Keçidin Alətlərini fərdiləşdir..."; + this.ribbonContextMenuShowBelow = " Sürətli Keçidin Alətlərini Menyu lentinin altında göstər "; + this.ribbonContextMenuShowAbove = " Sürətli Keçidin Alətlərini Menyu lentinin üstündə göstər "; + this.ribbonContextMenuCustomizeRibbon = "Menyu lentini fərdiləşdir..."; + this.ribbonContextMenuMinimizeRibbon = " Menyu lentini kiçilt"; + } + + #endregion + + #region Finnish + + private void LoadFinnish() + { + this.backstageButtonText = "Tiedosto"; + this.backstageButtonKeyTip = "T"; + this.minimizeButtonScreenTipTitle = "Pienennä valintanauha (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Näytä valintanauhassa vain välilehtien nimet"; + this.expandButtonScreenTipTitle = "Laajenna valintanauha (Ctrl + F1)"; + this.expandButtonScreenTipText = "Näytä valintanauha aina laajennettuna silloinkin, kun valitset komennon"; + this.quickAccessToolBarDropDownButtonTooltip = "Mukauta pikatyökaluriviä"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Lisää valintoja"; + this.quickAccessToolBarMenuHeader = "Mukauta pikatyökaluriviä"; + this.quickAccessToolBarMenuShowAbove = "Näytä valintanauhan yläpuolella"; + this.quickAccessToolBarMenuShowBelow = "Näytä valintanauhan alapuolella"; + this.ribbonContextMenuAddItem = "Lisää pikatyökaluriville"; + this.ribbonContextMenuAddGroup = "Lisää ryhmä pikatyökaluriviin"; + this.ribbonContextMenuAddGallery = "Lisää valikoima pikatyökaluriviin"; + this.ribbonContextMenuAddMenu = "Lisää valikko pikatyökaluriviin"; + this.ribbonContextMenuRemoveItem = "Poista pikatyökaluriviltä"; + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Mukauta pikatyökaluriviä..."; + this.ribbonContextMenuShowBelow = "Näytä pikatyökalurivi valintanauhan alapuolella"; + this.ribbonContextMenuShowAbove = "Näytä pikatyökalurivi valintanauhan yläpuolella"; + this.ribbonContextMenuCustomizeRibbon = "Mukauta valintanauhaa..."; + this.ribbonContextMenuMinimizeRibbon = "Pienennä valintanauha"; + this.screenTipDisableReasonHeader = "Tämä komento on tällä hetkellä poissa käytöstä"; + } + + #endregion + + #region Norwegian + + private void LoadNorwegian() + { + // Backstage button text & key tip + this.backstageButtonText = "Fil"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimer båndet (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Viser bare kategorinavnene på båndet"; + this.expandButtonScreenTipTitle = "Utvider båndet (Ctrl + F1)"; + this.expandButtonScreenTipText = "Vis båndet slik at det alltid er utvidet selv etter at du har valgt en kommando"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Tilpass verktøylinje for hurtigtilgang"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Flere kontroller"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Tilpass verktøylinje for hurtigtilgang"; + this.quickAccessToolBarMenuShowAbove = "Vis over båndet"; + this.quickAccessToolBarMenuShowBelow = "Vis under båndet"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Legg til på verktøylinje for hurtigtilgang"; // Button + this.ribbonContextMenuAddGroup = "Legg til gruppe på verktøylinje for hurtigtilgang"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Legg til galleri på verktøylinje for hurtigtilgang"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Legg til meny på verktøylinje for hurtigtilgang"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Fjern verktøylinjen for hurtigtilgang"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tilpass verktøylinje for hurtigtilgang..."; + this.ribbonContextMenuShowBelow = "Vis verktøylinjen for hurtigtilgang under båndet"; + this.ribbonContextMenuShowAbove = "Vis verktøylinjen for hurtigtilgang over båndet"; + this.ribbonContextMenuCustomizeRibbon = "Tilpass båndet..."; + this.ribbonContextMenuMinimizeRibbon = "Minimer båndet"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Denne kommandoen er for øyeblikket deaktivert."; + } + + #endregion + + #region Turkish + + private void LoadTurkish() + { + // Backstage button text & key tip + this.backstageButtonText = "Dosya"; + this.backstageButtonKeyTip = "D"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Şeridi Daralt (Ctrl+F1)"; + this.minimizeButtonScreenTipText = "Daha fazla alana mı\nihtiyacınız var? Şeridi daraltın, yalnızca sekme isimleri görünsün."; + this.expandButtonScreenTipTitle = "Şeridi Sabitle (Ctrl+F1)"; + this.expandButtonScreenTipText = "Şeridi görmek mi istiyorsunuz? Çalışırken açık tutun."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Diğer denetimler"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; + this.quickAccessToolBarMenuShowAbove = "Şeridin Üstünde Göster"; + this.quickAccessToolBarMenuShowBelow = "Şeridin Altında Göster"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Hızlı Erişim Araç Çubuğu'na Ekle"; // Button + this.ribbonContextMenuAddGroup = "Grubu Hızlı Erişim Araç Çubuğu'na Ekle"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Galeriyi Hızlı Erişim Araç Çubuğu'na Ekle"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Menüyü Hızlı Erişim Araç Çubuğu'na Ekle"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Hızlı Erişim Araç Çubuğu'ndan Kaldır"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Hızlı Erişim Araç Çubuğu'nu Özelleştir"; + this.ribbonContextMenuShowBelow = "Hızlı Erişim Araç Çubuğu'nu Şeridin Altında Göster"; + this.ribbonContextMenuShowAbove = "Hızlı Erişim Araç Çubuğu'nu Şeridin Üstünde Göster"; + this.ribbonContextMenuCustomizeRibbon = "Şeridi Özelleştir..."; + this.ribbonContextMenuMinimizeRibbon = "Şeridi Daralt"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Bu komut şu anda devre dışı"; + this.screenTipF1LabelHeader = "Yardım için F1'e basın."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Durum Çubuğunu Özelleştir"; + } + + #endregion + + #region Hebrew + + private void LoadHebrew() + { + // Backstage button text & key tip + this.backstageButtonText = "קובץ"; + this.backstageButtonKeyTip = "ק"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "מזער את רצועת הכלים (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "הצג רק את שמות הכרטיסיות\nברצועת הכלים."; + this.expandButtonScreenTipTitle = "הרחב את רצועת הכלים (Ctrl + F1)"; + this.expandButtonScreenTipText = "הצג את רצועת הכלים כשהיא\nמורחבת תמיד, גם לאחר\nשתלחץ על הפקודה."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "התאמה אישית של סרגל הכלים לגישה מהירה"; + this.quickAccessToolBarMoreControlsButtonTooltip = "פקודות נוספות"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "התאמה אישית של סרגל הכלים לגישה מהירה"; + this.quickAccessToolBarMenuShowAbove = "הצג מעל לרצועת הכלים"; + this.quickAccessToolBarMenuShowBelow = "הצג מעל לרצועת הכלים"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "הוסף לסרגל הכלים לגישה מהירה"; // Button + this.ribbonContextMenuAddGroup = "הוסף קבוצה לסרגל הכלים לגישה מהירה"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "הוסף גלריה לסרגל הכלים לגישה מהירה"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "הוסף תפריט לסרגל הכלים לגישה מהירה"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "הסר מסרגל הכלים לגישה מהירה"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "של סרגל הכלים רצועת הכלים..."; + this.ribbonContextMenuShowBelow = "הצג את סרגל הכלים לגישה מהירה מתחת לרצועת הכלים"; + this.ribbonContextMenuShowAbove = "הצג את סרגל הכלים לגישה מהירה מעל לרצועת הכלים"; + this.ribbonContextMenuCustomizeRibbon = "התאמה אישית של רצועת הכלים..."; + this.ribbonContextMenuMinimizeRibbon = "מזער את רצועת הכלים"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "פקודה זו אינה זמינה כעת."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "התאמה אישית של שורת המצב"; + } + + #endregion + + #region Greek + + private void LoadGreek() + { + // Backstage button text & key tip + this.backstageButtonText = "Αρχείο"; + this.backstageButtonKeyTip = "Α"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Ελαχιστοποίηση της Κορδέλας (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Εμφάνιση μόνο των ονομάτων καρτελών στην Κορδέλα."; + this.expandButtonScreenTipTitle = "Ανάπτυξη της Κορδέλας (Ctrl + F1)"; + this.expandButtonScreenTipText = "Εμφάνιση της Κορδέλας προκειμένου να αναπτύσσεται πάντα, ακόμα και αφού κάνετε κλικ σε μια εντολή."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Περισσότερες εντολές"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης"; + this.quickAccessToolBarMenuShowAbove = "Εμφάνιση πάνω από την Κορδέλα"; + this.quickAccessToolBarMenuShowBelow = "Εμφάνιση κάτω από την Κορδέλα"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Προσθήκη στη γραμμή εργαλείων γρήγορης πρόσβασης"; // Button + this.ribbonContextMenuAddGroup = "Προσθήκη ομάδας στη γραμμή εργαλείων γρήγορης πρόσβασης"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Προσθήκη συλλογής στη γραμμή εργαλείων γρήγορης πρόσβασης"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Προσθήκη μενού στη γραμμή εργαλείων γρήγορης πρόσβασης"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Κατάργηση από τη γραμμή εργαλείων γρήγορης πρόσβασης"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Προσαρμογή γραμμής εργαλείων γρήγορης πρόσβασης..."; + this.ribbonContextMenuShowBelow = "Εμφάνιση της γραμμής εργαλείων γρήγορης πρόσβασης κάτω από την Κορδέλα"; + this.ribbonContextMenuShowAbove = "Εμφάνιση της γραμμής εργαλείων γρήγορης πρόσβασης πάνω από την Κορδέλα"; + this.ribbonContextMenuCustomizeRibbon = "Προσαρμογή της Κορδέλας..."; + this.ribbonContextMenuMinimizeRibbon = "Ελαχιστοποίηση της Κορδέλας"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Αυτή η εντολή είναι απενεργοποιημένη προς το παρόν."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Προσαρμογή γραμμής κατάστασης"; + } + + #endregion + + #region Korean + + private void LoadKorean() + { + // Backstage button text & key tip + this.backstageButtonText = "파일"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "리본 메뉴를 최소화 합니다 (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "리본 메뉴를 표시하거나 숨깁니다\n\n리본 메뉴가 숨김 상태일때만,\n탭이름이 보여집니다"; + this.expandButtonScreenTipTitle = "리본 메뉴를 표시합니다 (Ctrl + F1)"; + this.expandButtonScreenTipText = "리본 메뉴를 표시하거나 숨깁니다\n\n리본 메뉴가 숨김 상태일때만,\n탭이름이 보여집니다"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "빠른 실행 도구 모음 사용자 지정"; + this.quickAccessToolBarMoreControlsButtonTooltip = "기타 컨트롤들"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "빠른 실행 도구 모음 사용자 지정"; + this.quickAccessToolBarMenuShowAbove = "리본 메뉴 위에 표시"; + this.quickAccessToolBarMenuShowBelow = "리본 메뉴 아래에 표시"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "빠른 실행 도구 모음에 추가"; // Button + this.ribbonContextMenuAddGroup = "그룹을 빠른 실행 도구 모음에 추가"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "갤러리를 빠른 실행 도구 모음에 추가"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "메뉴를 빠른 실행 도구 모음에 추가"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "빠른 실행 도구 모음에서 단추 제거"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "빠른 실행 도구 모음 사용자 지정..."; + this.ribbonContextMenuShowBelow = "리본 메뉴 아래에 빠른 실행 도구 모음 표시"; + this.ribbonContextMenuShowAbove = "리본 메뉴 위에 빠른 실행 도구 모음 표시"; + this.ribbonContextMenuCustomizeRibbon = "리본 메뉴 사용자 지정..."; + this.ribbonContextMenuMinimizeRibbon = "리본 메뉴 최소화"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "이 명령은 현재 사용할 수 없습니다."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "상태 표시줄 사용자 지정"; + } + + #endregion + + #region Lithuanian + + private void LoadLithuanian() + { + // Backstage button text & key tip + this.backstageButtonText = "Failas"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimizuoti juostelę (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Juostelėje rodyti tik skirtukų pavadinimus."; + this.expandButtonScreenTipTitle = "Išplėsti juostelę (Ctrl + F1)"; + this.expandButtonScreenTipText = "Rodyti juostelę taip, kad visada butų išskleista net ir spustelėjus komandą."; + + // QAT tooltips and menu items + + this.quickAccessToolBarDropDownButtonTooltip = "Tinkinti sparčiosios prieigos įrankių juostą"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Daugiau valdiklių"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Tinkinti sparčiosios prieigos įrankių juostą"; + this.quickAccessToolBarMenuShowAbove = "Rodyti virš juostelės"; + this.quickAccessToolBarMenuShowBelow = "Rodyti po juostele"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Pridėti į sparčiosios prieigos įrankių juostą"; // Button + this.ribbonContextMenuAddGroup = "Pridėti į sparčiosios prieigos įrankių juostą"; + this.ribbonContextMenuAddGallery = "Įtraukti galeriją į sparčiosios prieigos įrankių juostą"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Pridėti į sparčiosios prieigos įrankių juostą"; + this.ribbonContextMenuRemoveItem = "Šalinti iš sparčiosios prieigos įrankių juostos"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tinkinti sparčiosios prieigos įrankių juostą..."; + this.ribbonContextMenuShowBelow = "Rodyti po juostele"; + this.ribbonContextMenuShowAbove = "Rodyti virš juostelės"; + this.ribbonContextMenuCustomizeRibbon = "Tinkinti juostelę:"; + this.ribbonContextMenuMinimizeRibbon = "Minimizuoti juostelę"; + } + + #endregion + + #region Vietnamese + + private void LoadVietnamese() + { + // Backstage button text & key tip + this.backstageButtonText = "Tệp"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Thu gọn Ruy băng (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Hiện hoặc ẩn Ruy băng\n\nKhi Ruy băng ẩn, chỉ có tên thẻ được hiện"; + this.expandButtonScreenTipTitle = "Mở rộng Ruy băng (Ctrl + F1)"; + this.expandButtonScreenTipText = "Hiện hoặc ẩn Ruy băng\n\nKhi Ruy băng ẩn, chỉ có tên thẻ được hiện"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Tùy chỉnh thanh công cụ Truy cập nhanh"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Thêm điều khiển"; // khi có hai mũi tên ">>" + this.quickAccessToolBarMenuHeader = "Tùy chỉnh thanh công cụ Truy cập nhanh"; + this.quickAccessToolBarMenuShowAbove = "Hiện trên thanh Ruy băng"; + this.quickAccessToolBarMenuShowBelow = "Hiện dưới thanh Ruy băng"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Thêm vào thanh công cụ Truy cập nhanh"; // Button + this.ribbonContextMenuAddGroup = "Thêm nhóm vào thanh công cụ Truy cập nhanh"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Thêm bộ sưu tập vào thanh công cụ Truy cập nhanh"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Thêm menu vào thanh công cụ Truy cập nhanh"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Loại"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Tùy chỉnh thanh công cụ Truy cập nhanh..."; + this.ribbonContextMenuShowBelow = "Hiện thanh công cụ truy cập nhanh dưới thanh Ruy băng"; + this.ribbonContextMenuShowAbove = "Hiện thanh công cụ truy cập nhanh trên thanh Ruy băng"; + this.ribbonContextMenuCustomizeRibbon = "Tùy biến thanh Ruy băng..."; + this.ribbonContextMenuMinimizeRibbon = "Thu gọn Ruy băng"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Lệnh này hiện bị tắt."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Tùy biến thanh Trạng thái"; + } + + #endregion + + #region Sinhala (Sri Lanka) + + private void LoadSinhala() + { + // Backstage button text & key tip + this.backstageButtonText = "ගොනුව"; + this.backstageButtonKeyTip = "න1"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "රිබනය හකුළන්න (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "රිබනය මත පටිති නාම පමණක් පෙන්වන්න."; + this.expandButtonScreenTipTitle = "රිබනය විහිදන්න (Ctrl + F1)"; + this.expandButtonScreenTipText = "රිබනය පෙන්වන්න, එවිට ඔබ\n\n විධානයක් ක්ලික් කළද එය\n\n සැමවිටම විහිදී පවතී."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය"; + this.quickAccessToolBarMoreControlsButtonTooltip = "තවත් විධාන"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය"; + this.quickAccessToolBarMenuShowAbove = "රිබනයට ඉහලින් පෙන්වන්න"; + this.quickAccessToolBarMenuShowBelow = "රිබනයට පහලින් පෙන්වන්න"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට එක් කරන්න"; // Button + this.ribbonContextMenuAddGroup = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට එක් කරන්න"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට ගැලරිය එක් කරන්න"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයට මෙනුව එක් කරන්න"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරයෙන් ඉවත් කරන්න"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය අභිමත කරණය කරන්න..."; + this.ribbonContextMenuShowBelow = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය රිබනයට පහලින් පෙන්වන්න"; + this.ribbonContextMenuShowAbove = "ඉක්මන් ප්‍රෙව්ශ මෙවලම් තීරය රිබනයට ඉහලින් පෙන්වන්න"; + this.ribbonContextMenuCustomizeRibbon = "රිබනය අභිමත කරණය කරන්න..."; + this.ribbonContextMenuMinimizeRibbon = "රිබනය හකුළන්න"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "මෙම විධානය දැනට භාවිතා කළ නොහැක"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "තත්ව තීරුව අභිමත කරණය"; + } + + #endregion + + #region Slovenian + + private void LoadSlovenian() + { + // Backstage button text & key tip + this.backstageButtonText = "Datoteka"; + this.backstageButtonKeyTip = "D"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Minimiraj trak (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Pokaži ali skrij trak\n\nKo je trak skrit, so prikazani samo zavihki"; + this.expandButtonScreenTipTitle = "Razširi trak (Ctrl + F1)"; + this.expandButtonScreenTipText = "Pokaži ali skrij trak\n\nKo je trak skrit, so prikazani samo zavihki"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Prilagodi orodno vrstico za hitri dostop"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Več ukazov"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Prilagodi orodno vrstico za hitri dostop"; + this.quickAccessToolBarMenuShowAbove = "Pokaži nad trakom"; + this.quickAccessToolBarMenuShowBelow = "Pokaži pod trakom"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Dodaj v orodno vrstico za hitri dostop"; // Button + this.ribbonContextMenuAddGroup = "Dodaj skupino orodni vrstici za hitri dostop"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Dodaj galerijo orodni vrstici za hitri dostop"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Dodaj meni orodni vrstici za hitri dostop"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Odstrani iz orodne vrstice za hitri dostop"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Prilagodi orodno vrstico za hitri dostop..."; + this.ribbonContextMenuShowBelow = "Pokaži orodno vrstico za hitri dostop pod trakom"; + this.ribbonContextMenuShowAbove = "Pokaži orodno vrstico za hitri dostop nad trakom"; + this.ribbonContextMenuCustomizeRibbon = "Prilagodi trak..."; + this.ribbonContextMenuMinimizeRibbon = "Minimiraj trak"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "Ta ukaz je trenutno onemogočen."; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Prilagodi vrstico stanja"; + } + + #endregion + + #region Catalan + + private void LoadCatalan() + { + // Backstage button text & key tip + this.backstageButtonText = "Fitxer"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + // TRANSLATOR'S NOTE: This block is not shown at Windows 7's Apps (WordPad or Paint) + this.minimizeButtonScreenTipTitle = "Minimitza la cinta (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "Ensenya o amaga la cinta\n\nQuan la cinta no es mostri, només s'ensenyen els noms de les pestanyes"; + this.expandButtonScreenTipTitle = "Expandeix la cinta (Ctrl + F1)"; + this.expandButtonScreenTipText = "Ensenya o amaga la cinta\n\nQuan la cinta no es mostri, només s'ensenyen els noms de les pestanyes"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Personalitza la barra d'eines d'accés ràpid"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Més controls"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Personalitza la barra d'eines d'accés ràpid"; + this.quickAccessToolBarMenuShowAbove = "Mostra sobre la cinta"; + this.quickAccessToolBarMenuShowBelow = "Mostra sota la cinta"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Afegeix a la barra d'eines d'accés ràpid"; // Button + this.ribbonContextMenuAddGroup = "Afegeix grup a la barra d'eines d'accés ràpid"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Afegeix galeria a la barra d'eines d'accés ràpid"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Afegeix menú a la barra d'eines d'accés ràpid"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Elimina la barra d'eines d'accés ràpid"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Personalitza la barra d'eines d'accés ràpid..."; + this.ribbonContextMenuShowBelow = "Mostra la barra d'eines d'accés ràpid sota la cinta"; + this.ribbonContextMenuShowAbove = "Mostra la barra d'eines d'accés ràpid sobre la cinta"; + this.ribbonContextMenuCustomizeRibbon = "Personalitza la cinta..."; + this.ribbonContextMenuMinimizeRibbon = "Minimitza la cinta"; + } + + #endregion + + #region Estonian + + private void LoadEstonian() + { + // Backstage button text & key tip + this.backstageButtonText = "Fail"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "Ahenda menüülint (Ctrl+F1)"; + this.minimizeButtonScreenTipText = "Kas vajate rohkem ruumi? Ahendage lint, siis kuvatakse \nainult menüünimed."; + this.expandButtonScreenTipTitle = "Kinnita lint (Ctrl+F1)"; + this.expandButtonScreenTipText = "Kas soovite, et lint oleks kuvatud? Saate selle töötamise \najal avatuna hoida."; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "Kohanda kiirpääsuriba"; + this.quickAccessToolBarMoreControlsButtonTooltip = "Rohkem juhtelemente"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "Kohanda kiirpääsuriba"; + this.quickAccessToolBarMenuShowAbove = "Kuva lindi kohal"; + this.quickAccessToolBarMenuShowBelow = "Kuva lindi all"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "Lisa kiirpääsuribale"; // Button + this.ribbonContextMenuAddGroup = "Lisa rühm kiirpääsuribale"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "Lisa galerii kiirpääsuribale"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "Lisa menüü kiirpääsuribale"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "Eemalda kiirpääsuribalt"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "Kohanda kiirpääsuriba..."; + this.ribbonContextMenuShowBelow = "Kuva kiirpääsuriba lindi all"; + this.ribbonContextMenuShowAbove = "Kuva kiirpääsuriba lindi kohal"; + this.ribbonContextMenuCustomizeRibbon = "Kohanda linti..."; + this.ribbonContextMenuMinimizeRibbon = "Ahenda menüülint"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + //Screentips + this.screenTipDisableReasonHeader = "See käsk on praegu keelatud."; + this.screenTipF1LabelHeader = "Spikri kuvamiseks vajutage klahvi F1"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "Kohanda olekuriba"; + } + + #endregion + + //Add by gamegear.tw + //Note: Adding Tradchinese + #region TradChinese + private void LoadTradChinese() + { + // Backstage button text & key tip + this.backstageButtonText = "檔案"; + this.backstageButtonKeyTip = "F"; + + // See right-top corner... (two different tooltips must be if you press it) + this.minimizeButtonScreenTipTitle = "功能區最小化 (Ctrl + F1)"; + this.minimizeButtonScreenTipText = "僅顯示功能區上的選項名稱,點擊選項後可顯示命令。"; + this.expandButtonScreenTipTitle = "展開功能區 (Ctrl + F1)"; + this.expandButtonScreenTipText = "始終顯示功能區選項及命令。"; + + // QAT tooltips and menu items + this.quickAccessToolBarDropDownButtonTooltip = "自訂快速存取工具列"; + this.quickAccessToolBarMoreControlsButtonTooltip = "其他命令"; // When two arrows appear ">>" + this.quickAccessToolBarMenuHeader = "自訂快速存取工具列"; + this.quickAccessToolBarMenuShowAbove = "在功能區上方顯示"; + this.quickAccessToolBarMenuShowBelow = "在功能區下方顯示"; + + // Click on Ribbon to show context menu + this.ribbonContextMenuAddItem = "新增到快速存取工具列"; // Button + this.ribbonContextMenuAddGroup = "將群組新增到快速存取工具列"; // For ex., by collapsed group + this.ribbonContextMenuAddGallery = "將樣式新增到快速存取工具列"; // For ex., by opened font context menu + this.ribbonContextMenuAddMenu = "將選單新增到快速存取工具列"; // By dashed splitter in context menu + this.ribbonContextMenuRemoveItem = "將選單從快速存取工具列中移除"; // By item in QAT + this.ribbonContextMenuCustomizeQuickAccessToolbar = "自訂快速存取工具列..."; + this.ribbonContextMenuShowBelow = "在功能表下方顯示快速存取工具列"; + this.ribbonContextMenuShowAbove = "在功能表上方顯示快速存取工具列"; + this.ribbonContextMenuCustomizeRibbon = "自訂功能區..."; + this.ribbonContextMenuMinimizeRibbon = "功能區最小化"; + + // To see it in Word: open *.doc (not *.docx) and see Insert->Screenshot + // (This prop was introduced after v1.3) + this.screenTipDisableReasonHeader = "命令已被禁用。"; + + // Right-click on status bar to see it. NEW! from v2.0 + this.customizeStatusBar = "自訂狀態工具列"; + } + #endregion + + + } +} diff --git a/Fluent/RibbonToolBarTray.cs b/Fluent.Ribbon/RibbonToolBarTray.cs similarity index 97% rename from Fluent/RibbonToolBarTray.cs rename to Fluent.Ribbon/RibbonToolBarTray.cs index ed620233d..09f8130be 100644 --- a/Fluent/RibbonToolBarTray.cs +++ b/Fluent.Ribbon/RibbonToolBarTray.cs @@ -1,403 +1,403 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion -using System; -using System.Windows; -using System.Windows.Markup; -using System.Windows.Controls; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Fluent -{ - /// - /// Represents panel to layout ribbon controls in toolbar style - /// - [ContentProperty("Children")] - public class RibbonToolBarTray : Panel - { - #region Fields - - int[][] condensedOrder; - - #endregion - - #region Properties - - #region Condensed Order - - /// - /// Gets or sets order of elements in condensed state - /// (for example, 0,1,2;3,4;5,6) - /// - public string CondensedOrder - { - get { return (string)GetValue(CondensedOrderProperty); } - set { SetValue(CondensedOrderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CondensedOrder. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty CondensedOrderProperty = - DependencyProperty.Register("CondensedOrder", typeof(string), typeof(RibbonToolBarTray), new FrameworkPropertyMetadata(null, - FrameworkPropertyMetadataOptions.AffectsMeasure | - FrameworkPropertyMetadataOptions.AffectsArrange | - FrameworkPropertyMetadataOptions.AffectsRender, OnCondensedOrderPropertyChanged)); - - static void OnCondensedOrderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - RibbonToolBarTray tray = (RibbonToolBarTray)d; - string[] rows = ((string)e.NewValue).Split(';'); - tray.condensedOrder = new int[3][]; - bool errorOccured = false; - for (int i = 0; i < 3; i++) - { - if (i + 1 > rows.Length) { tray.condensedOrder[i] = new int[0]; continue; } - tray.condensedOrder[i] = rows[i].Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) - .Select(x => { - int result = 0; - errorOccured = errorOccured || !Int32.TryParse(x, out result); - return result; }).ToArray(); - } - System.Diagnostics.Debug.WriteLineIf(errorOccured, "The property CondensedOrder has incorrect formatted value " + e.NewValue); - } - - #endregion - - #region IsCondensed - - // TODO: add behavior to toolbar tray corresponds current size of the ribbon groupbox - - /// - /// Gets or sets whether the tray is condensed state - /// (i.e. three lines layout) - /// - public bool IsCondensed - { - get { return (bool)GetValue(IsCondensedProperty); } - set { SetValue(IsCondensedProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for IsCondensed. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IsCondensedProperty = - DependencyProperty.Register("IsCondensed", typeof(bool), typeof(RibbonToolBarTray), new FrameworkPropertyMetadata(false, - FrameworkPropertyMetadataOptions.AffectsMeasure | - FrameworkPropertyMetadataOptions.AffectsArrange | - FrameworkPropertyMetadataOptions.AffectsRender)); - - - #endregion - - #endregion - - #region Initialization - - /// - /// Default constructor - /// - public RibbonToolBarTray() - { - - } - - #endregion - - #region Layout - - /// - /// When overridden in a derived class, measures the size - /// in layout required for child elements and determines a - /// size for the System.Windows.FrameworkElement-derived class. - /// - /// The available size that this element can give to child elements - /// The size that this element determines - protected override Size MeasureOverride(Size availableSize) - { - MeasureChildren(); - - - if (IsCondensed && CondensedOrder == null) - { - // if condensed order is not present, we make automatic order - condensedOrder = new int[3][] { new int[0], new int[0], new int[0] }; - - double totalWidth = GetChildrenWidth(); - double threshold = totalWidth / 3.0; - - double x = 0; - bool hasStretchable = false; - int nextStartIndex = 0; - int currentRow = 0; - for (int i = 0; i < Children.Count; i++) - { - Size desiredSize = Children[i].DesiredSize; - if (x + desiredSize.Width > threshold) - { - // Break to next row - x = 0; - - // If the current row has a stretchable control - // we split before the current control to make the next row larger - if (hasStretchable) - { - hasStretchable = false; - condensedOrder[currentRow] = MakeArray(nextStartIndex, i - 1); - nextStartIndex = i; - currentRow++; - if (currentRow == 2) - { - condensedOrder[currentRow] = MakeArray(nextStartIndex, Children.Count - 1); - break; - } - } - else - { - condensedOrder[currentRow] = MakeArray(nextStartIndex, i); - nextStartIndex = i + 1; - currentRow++; - if (currentRow == 2) - { - condensedOrder[currentRow] = MakeArray(nextStartIndex, Children.Count - 1); - break; - } - continue; - } - } - - x += desiredSize.Width; - if ((Children[i] as FrameworkElement).HorizontalAlignment == HorizontalAlignment.Stretch) - hasStretchable = true; - } - - } - - if (IsCondensed) - { - double maxWidth; - double[] widths; - CalculateCondensedWidths(condensedOrder, out maxWidth, out widths); - return new Size(maxWidth, Double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height); - } - else - { - int breakIndex; - double firstPartWidth; - double maxWidth; - FindWhereWeCanSplitUncondensed(out breakIndex, out firstPartWidth, out maxWidth); - - return new Size(maxWidth, Double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height); - } - } - - // Summ all width of all children - double GetChildrenWidth() - { - double width = 0; - foreach (UIElement element in InternalChildren) width += element.DesiredSize.Width; - return width; - } - - // Measures children - void MeasureChildren() - { - Size size = new Size(Double.PositiveInfinity, Double.PositiveInfinity); - foreach (FrameworkElement element in Children) - { - if (element.HorizontalAlignment == HorizontalAlignment.Stretch) - element.Measure(new Size(element.MinWidth, Double.PositiveInfinity)); - else element.Measure(size); - } - } - - /// - /// When overridden in a derived class, positions child elements and determines - /// a size for a System.Windows.FrameworkElement derived class - /// - /// The final area within the parent that this - /// element should use to arrange itself and its children - /// The actual size used - protected override Size ArrangeOverride(Size finalSize) - { - if (Children.Count == 0) return finalSize; - - return IsCondensed ? - ArrangeCondensed(condensedOrder, finalSize) : - ArrangeUncondensed(finalSize); - } - - static int[] MakeArray(int from, int to) - { - int[] array = new int[to - from + 1]; - for (int i = from; i <= to; i++) - { - array[i - from] = i; - } - return array; - } - - Size ArrangeUncondensed(Size finalSize) - { - if (Children.Count == 0) return finalSize; - - double childrenHeight = Children[0].DesiredSize.Height; - double totalWidth = GetChildrenWidth(); - - int breakIndex; - double firstPartWidth; - double maxWidth; - FindWhereWeCanSplitUncondensed(out breakIndex, out firstPartWidth, out maxWidth); - - - // Arranging - double space = (finalSize.Height - (childrenHeight * 2.0)) / 3.0; - double y = space; - double x = 0; - bool stillSeekStretching = true; - for (int i = 0; i < Children.Count; i++) - { - if (i == breakIndex) - { - x = 0; - stillSeekStretching = true; - y += space + childrenHeight; - } - - FrameworkElement element = Children[i] as FrameworkElement; - if (element == null) continue; - if (stillSeekStretching && element.HorizontalAlignment == HorizontalAlignment.Stretch) - { - stillSeekStretching = false; - double w = maxWidth - (i >= breakIndex ? totalWidth - firstPartWidth : firstPartWidth) + element.DesiredSize.Width; - element.Arrange(new Rect(x, y, w, childrenHeight)); - x += w; - } - else - { - element.Arrange(new Rect(x, y, element.DesiredSize.Width, childrenHeight)); - x += element.DesiredSize.Width; - } - - } - - return finalSize; - } - - // Calculates where we can split and widths - void FindWhereWeCanSplitUncondensed(out int breakIndex, out double firstPartWidth, out double maxWidth) - { - double totalWidth = GetChildrenWidth(); - double threshold = totalWidth / 2.0; - - // Find where we can split/ break - double x = 0; - bool hasStretchable = false; - breakIndex = 0; - firstPartWidth = 0; - for (int i = 0; i < Children.Count; i++) - { - Size desiredSize = Children[i].DesiredSize; - if ((x + desiredSize.Width > threshold) && (i != 0)) - { - if (hasStretchable) - { - breakIndex = i; - firstPartWidth = x; - } - else - { - breakIndex = i + 1; - firstPartWidth = x + desiredSize.Width; - } - break; - } - - x += desiredSize.Width; - if ((Children[i] as FrameworkElement).HorizontalAlignment == HorizontalAlignment.Stretch) - hasStretchable = true; - } - maxWidth = Math.Max(firstPartWidth, totalWidth - firstPartWidth); - } - - // Arranges children using the given condensedOrder - Size ArrangeCondensed(int[][] order, Size finalSize) - { - if (Children.Count == 0) return finalSize; - double childrenHeight = Children[0].DesiredSize.Height; - - double maxWidth; - double[] widths; - CalculateCondensedWidths(order, out maxWidth, out widths); - - // Removes skipped items - if (order[0].Length + order[1].Length + order[2].Length < Children.Count) - { - // TODO: fix this dirty way to hide skipped controls in toolbar tray - Rect empty = new Rect(-10000, -10000, 0.01, 0.01); - foreach (UIElement item in Children) item.Arrange(empty); - } - - // Arranging - double space = (finalSize.Height - (childrenHeight * 3.0)) / 4.0; - double y = space; - for (int i = 0; i < 3; i++) - { - double x = 0; - bool stillSeekStretching = true; - for (int j = 0; j < order[i].Length; j++) - { - FrameworkElement element = Children[order[i][j]] as FrameworkElement; - if (element == null) continue; - if (stillSeekStretching && element.HorizontalAlignment == HorizontalAlignment.Stretch) - { - // We have found a stretchable item. - // Let the stretchable item take all - // available space in the current row - stillSeekStretching = false; - double w = maxWidth - widths[i] + element.DesiredSize.Width; - element.Arrange(new Rect(x, y, w, childrenHeight)); - x += w; - } - else - { - element.Arrange(new Rect(x, y, element.DesiredSize.Width, childrenHeight)); - x += element.DesiredSize.Width; - } - } - y += childrenHeight + space; - } - - return new Size(maxWidth, finalSize.Height); - } - - void CalculateCondensedWidths(int[][] order, out double maxWidth, out double[] widths) - { - // Calculate max width - maxWidth = 0; - widths = new double[3]; - for (int i = 0; i < 3; i++) - { - // Calculate max width - double width = 0; - for (int j = 0; j < order[i].Length; j++) - { - width += Children[order[i][j]].DesiredSize.Width; - } - widths[i] = width; - maxWidth = Math.Max(maxWidth, width); - } - } - - #endregion - } -} +#region Copyright and License Information +// Fluent Ribbon Control Suite +// http://fluent.codeplex.com/ +// Copyright � Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. +// +// Distributed under the terms of the Microsoft Public License (Ms-PL). +// The license is available online http://fluent.codeplex.com/license +#endregion +using System; +using System.Windows; +using System.Windows.Markup; +using System.Windows.Controls; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Fluent +{ + /// + /// Represents panel to layout ribbon controls in toolbar style + /// + [ContentProperty("Children")] + public class RibbonToolBarTray : Panel + { + #region Fields + + int[][] condensedOrder; + + #endregion + + #region Properties + + #region Condensed Order + + /// + /// Gets or sets order of elements in condensed state + /// (for example, 0,1,2;3,4;5,6) + /// + public string CondensedOrder + { + get { return (string)GetValue(CondensedOrderProperty); } + set { SetValue(CondensedOrderProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for CondensedOrder. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty CondensedOrderProperty = + DependencyProperty.Register("CondensedOrder", typeof(string), typeof(RibbonToolBarTray), new FrameworkPropertyMetadata(null, + FrameworkPropertyMetadataOptions.AffectsMeasure | + FrameworkPropertyMetadataOptions.AffectsArrange | + FrameworkPropertyMetadataOptions.AffectsRender, OnCondensedOrderPropertyChanged)); + + static void OnCondensedOrderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + RibbonToolBarTray tray = (RibbonToolBarTray)d; + string[] rows = ((string)e.NewValue).Split(';'); + tray.condensedOrder = new int[3][]; + bool errorOccured = false; + for (int i = 0; i < 3; i++) + { + if (i + 1 > rows.Length) { tray.condensedOrder[i] = new int[0]; continue; } + tray.condensedOrder[i] = rows[i].Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => { + int result = 0; + errorOccured = errorOccured || !Int32.TryParse(x, out result); + return result; }).ToArray(); + } + System.Diagnostics.Debug.WriteLineIf(errorOccured, "The property CondensedOrder has incorrect formatted value " + e.NewValue); + } + + #endregion + + #region IsCondensed + + // TODO: add behavior to toolbar tray corresponds current size of the ribbon groupbox + + /// + /// Gets or sets whether the tray is condensed state + /// (i.e. three lines layout) + /// + public bool IsCondensed + { + get { return (bool)GetValue(IsCondensedProperty); } + set { SetValue(IsCondensedProperty, value); } + } + + /// + /// Using a DependencyProperty as the backing store for IsCondensed. + /// This enables animation, styling, binding, etc... + /// + public static readonly DependencyProperty IsCondensedProperty = + DependencyProperty.Register("IsCondensed", typeof(bool), typeof(RibbonToolBarTray), new FrameworkPropertyMetadata(false, + FrameworkPropertyMetadataOptions.AffectsMeasure | + FrameworkPropertyMetadataOptions.AffectsArrange | + FrameworkPropertyMetadataOptions.AffectsRender)); + + + #endregion + + #endregion + + #region Initialization + + /// + /// Default constructor + /// + public RibbonToolBarTray() + { + + } + + #endregion + + #region Layout + + /// + /// When overridden in a derived class, measures the size + /// in layout required for child elements and determines a + /// size for the System.Windows.FrameworkElement-derived class. + /// + /// The available size that this element can give to child elements + /// The size that this element determines + protected override Size MeasureOverride(Size availableSize) + { + MeasureChildren(); + + + if (IsCondensed && CondensedOrder == null) + { + // if condensed order is not present, we make automatic order + condensedOrder = new int[3][] { new int[0], new int[0], new int[0] }; + + double totalWidth = GetChildrenWidth(); + double threshold = totalWidth / 3.0; + + double x = 0; + bool hasStretchable = false; + int nextStartIndex = 0; + int currentRow = 0; + for (int i = 0; i < Children.Count; i++) + { + Size desiredSize = Children[i].DesiredSize; + if (x + desiredSize.Width > threshold) + { + // Break to next row + x = 0; + + // If the current row has a stretchable control + // we split before the current control to make the next row larger + if (hasStretchable) + { + hasStretchable = false; + condensedOrder[currentRow] = MakeArray(nextStartIndex, i - 1); + nextStartIndex = i; + currentRow++; + if (currentRow == 2) + { + condensedOrder[currentRow] = MakeArray(nextStartIndex, Children.Count - 1); + break; + } + } + else + { + condensedOrder[currentRow] = MakeArray(nextStartIndex, i); + nextStartIndex = i + 1; + currentRow++; + if (currentRow == 2) + { + condensedOrder[currentRow] = MakeArray(nextStartIndex, Children.Count - 1); + break; + } + continue; + } + } + + x += desiredSize.Width; + if ((Children[i] as FrameworkElement).HorizontalAlignment == HorizontalAlignment.Stretch) + hasStretchable = true; + } + + } + + if (IsCondensed) + { + double maxWidth; + double[] widths; + CalculateCondensedWidths(condensedOrder, out maxWidth, out widths); + return new Size(maxWidth, Double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height); + } + else + { + int breakIndex; + double firstPartWidth; + double maxWidth; + FindWhereWeCanSplitUncondensed(out breakIndex, out firstPartWidth, out maxWidth); + + return new Size(maxWidth, Double.IsPositiveInfinity(availableSize.Height) ? 0 : availableSize.Height); + } + } + + // Summ all width of all children + double GetChildrenWidth() + { + double width = 0; + foreach (UIElement element in InternalChildren) width += element.DesiredSize.Width; + return width; + } + + // Measures children + void MeasureChildren() + { + Size size = new Size(Double.PositiveInfinity, Double.PositiveInfinity); + foreach (FrameworkElement element in Children) + { + if (element.HorizontalAlignment == HorizontalAlignment.Stretch) + element.Measure(new Size(element.MinWidth, Double.PositiveInfinity)); + else element.Measure(size); + } + } + + /// + /// When overridden in a derived class, positions child elements and determines + /// a size for a System.Windows.FrameworkElement derived class + /// + /// The final area within the parent that this + /// element should use to arrange itself and its children + /// The actual size used + protected override Size ArrangeOverride(Size finalSize) + { + if (Children.Count == 0) return finalSize; + + return IsCondensed ? + ArrangeCondensed(condensedOrder, finalSize) : + ArrangeUncondensed(finalSize); + } + + static int[] MakeArray(int from, int to) + { + int[] array = new int[to - from + 1]; + for (int i = from; i <= to; i++) + { + array[i - from] = i; + } + return array; + } + + Size ArrangeUncondensed(Size finalSize) + { + if (Children.Count == 0) return finalSize; + + double childrenHeight = Children[0].DesiredSize.Height; + double totalWidth = GetChildrenWidth(); + + int breakIndex; + double firstPartWidth; + double maxWidth; + FindWhereWeCanSplitUncondensed(out breakIndex, out firstPartWidth, out maxWidth); + + + // Arranging + double space = (finalSize.Height - (childrenHeight * 2.0)) / 3.0; + double y = space; + double x = 0; + bool stillSeekStretching = true; + for (int i = 0; i < Children.Count; i++) + { + if (i == breakIndex) + { + x = 0; + stillSeekStretching = true; + y += space + childrenHeight; + } + + FrameworkElement element = Children[i] as FrameworkElement; + if (element == null) continue; + if (stillSeekStretching && element.HorizontalAlignment == HorizontalAlignment.Stretch) + { + stillSeekStretching = false; + double w = maxWidth - (i >= breakIndex ? totalWidth - firstPartWidth : firstPartWidth) + element.DesiredSize.Width; + element.Arrange(new Rect(x, y, w, childrenHeight)); + x += w; + } + else + { + element.Arrange(new Rect(x, y, element.DesiredSize.Width, childrenHeight)); + x += element.DesiredSize.Width; + } + + } + + return finalSize; + } + + // Calculates where we can split and widths + void FindWhereWeCanSplitUncondensed(out int breakIndex, out double firstPartWidth, out double maxWidth) + { + double totalWidth = GetChildrenWidth(); + double threshold = totalWidth / 2.0; + + // Find where we can split/ break + double x = 0; + bool hasStretchable = false; + breakIndex = 0; + firstPartWidth = 0; + for (int i = 0; i < Children.Count; i++) + { + Size desiredSize = Children[i].DesiredSize; + if ((x + desiredSize.Width > threshold) && (i != 0)) + { + if (hasStretchable) + { + breakIndex = i; + firstPartWidth = x; + } + else + { + breakIndex = i + 1; + firstPartWidth = x + desiredSize.Width; + } + break; + } + + x += desiredSize.Width; + if ((Children[i] as FrameworkElement).HorizontalAlignment == HorizontalAlignment.Stretch) + hasStretchable = true; + } + maxWidth = Math.Max(firstPartWidth, totalWidth - firstPartWidth); + } + + // Arranges children using the given condensedOrder + Size ArrangeCondensed(int[][] order, Size finalSize) + { + if (Children.Count == 0) return finalSize; + double childrenHeight = Children[0].DesiredSize.Height; + + double maxWidth; + double[] widths; + CalculateCondensedWidths(order, out maxWidth, out widths); + + // Removes skipped items + if (order[0].Length + order[1].Length + order[2].Length < Children.Count) + { + // TODO: fix this dirty way to hide skipped controls in toolbar tray + Rect empty = new Rect(-10000, -10000, 0.01, 0.01); + foreach (UIElement item in Children) item.Arrange(empty); + } + + // Arranging + double space = (finalSize.Height - (childrenHeight * 3.0)) / 4.0; + double y = space; + for (int i = 0; i < 3; i++) + { + double x = 0; + bool stillSeekStretching = true; + for (int j = 0; j < order[i].Length; j++) + { + FrameworkElement element = Children[order[i][j]] as FrameworkElement; + if (element == null) continue; + if (stillSeekStretching && element.HorizontalAlignment == HorizontalAlignment.Stretch) + { + // We have found a stretchable item. + // Let the stretchable item take all + // available space in the current row + stillSeekStretching = false; + double w = maxWidth - widths[i] + element.DesiredSize.Width; + element.Arrange(new Rect(x, y, w, childrenHeight)); + x += w; + } + else + { + element.Arrange(new Rect(x, y, element.DesiredSize.Width, childrenHeight)); + x += element.DesiredSize.Width; + } + } + y += childrenHeight + space; + } + + return new Size(maxWidth, finalSize.Height); + } + + void CalculateCondensedWidths(int[][] order, out double maxWidth, out double[] widths) + { + // Calculate max width + maxWidth = 0; + widths = new double[3]; + for (int i = 0; i < 3; i++) + { + // Calculate max width + double width = 0; + for (int j = 0; j < order[i].Length; j++) + { + width += Children[order[i][j]].DesiredSize.Width; + } + widths[i] = width; + maxWidth = Math.Max(maxWidth, width); + } + } + + #endregion + } +} diff --git a/Fluent/Services/ContextMenuService.cs b/Fluent.Ribbon/Services/ContextMenuService.cs similarity index 97% rename from Fluent/Services/ContextMenuService.cs rename to Fluent.Ribbon/Services/ContextMenuService.cs index 696a20691..cd7659486 100644 --- a/Fluent/Services/ContextMenuService.cs +++ b/Fluent.Ribbon/Services/ContextMenuService.cs @@ -1,47 +1,47 @@ -using System; -using System.Windows; - -namespace Fluent -{ - /// - /// Represents additional context menu service - /// - public static class ContextMenuService - { - /// - /// Attach needed parameters to control - /// - /// - public static void Attach(Type type) - { - System.Windows.Controls.ContextMenuService.ShowOnDisabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(true)); - FrameworkElement.ContextMenuProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, OnContextMenuChanged, CoerceContextMenu)); - } - - private static void OnContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - d.CoerceValue(FrameworkElement.ContextMenuProperty); - } - - private static object CoerceContextMenu(DependencyObject d, object basevalue) - { - var control = d as IQuickAccessItemProvider; - if (basevalue == null - && (control == null || control.CanAddToQuickAccessToolBar)) - { - return Ribbon.RibbonContextMenu; - } - - return basevalue; - } - - /// - /// Coerce control context menu - /// - /// Control - public static void Coerce(DependencyObject o) - { - o.CoerceValue(FrameworkElement.ContextMenuProperty); - } - } +using System; +using System.Windows; + +namespace Fluent +{ + /// + /// Represents additional context menu service + /// + public static class ContextMenuService + { + /// + /// Attach needed parameters to control + /// + /// + public static void Attach(Type type) + { + System.Windows.Controls.ContextMenuService.ShowOnDisabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(true)); + FrameworkElement.ContextMenuProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, OnContextMenuChanged, CoerceContextMenu)); + } + + private static void OnContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + d.CoerceValue(FrameworkElement.ContextMenuProperty); + } + + private static object CoerceContextMenu(DependencyObject d, object basevalue) + { + var control = d as IQuickAccessItemProvider; + if (basevalue == null + && (control == null || control.CanAddToQuickAccessToolBar)) + { + return Ribbon.RibbonContextMenu; + } + + return basevalue; + } + + /// + /// Coerce control context menu + /// + /// Control + public static void Coerce(DependencyObject o) + { + o.CoerceValue(FrameworkElement.ContextMenuProperty); + } + } } \ No newline at end of file diff --git a/Fluent/Services/KeyTipService.cs b/Fluent.Ribbon/Services/KeyTipService.cs similarity index 62% rename from Fluent/Services/KeyTipService.cs rename to Fluent.Ribbon/Services/KeyTipService.cs index a9525378f..193187f37 100644 --- a/Fluent/Services/KeyTipService.cs +++ b/Fluent.Ribbon/Services/KeyTipService.cs @@ -1,428 +1,477 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright ?Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace Fluent -{ - using System; - using System.ComponentModel; - using System.Windows; - using System.Windows.Input; - using System.Windows.Interop; - using System.Windows.Threading; - using Fluent.Internal; - using Fluent.Metro.Native; - - /// - /// Handles Alt, F10 and so on - /// - internal class KeyTipService - { - #region Fields - - // Host element, usually this is Ribbon - private readonly Ribbon ribbon; - - // Timer to show KeyTips with delay - private readonly DispatcherTimer timer; - - // Is KeyTips Actived now - private KeyTipAdorner activeAdornerChain; - // This element must be remembered to restore it - IInputElement backUpFocusedElement; - // Window where we attached - private Window window; - - // Whether we attached to window - private bool attached; - - // Attached HWND source - private HwndSource attachedHwndSource; - - private static readonly KeyConverter keyConverter = new KeyConverter(); - private string currentUserInput; - - /// - /// Checks if any keytips are visible. - /// - public bool AreAnyKeyTipsVisible - { - get - { - if (this.activeAdornerChain != null) - { - return this.activeAdornerChain.AreAnyKeyTipsVisible; - } - - return false; - } - } - - #endregion - - #region Initialization - - /// - /// Default constrctor - /// - /// Host element - public KeyTipService(Ribbon ribbon) - { - this.ribbon = ribbon; - - if (this.ribbon.IsLoaded == false) - { - this.ribbon.Loaded += this.OnDelayedInitialization; - } - else - { - this.Attach(); - } - - // Initialize timer - this.timer = new DispatcherTimer(TimeSpan.FromSeconds(0.7), DispatcherPriority.SystemIdle, this.OnDelayedShow, Dispatcher.CurrentDispatcher); - this.timer.Stop(); - } - - private void OnDelayedInitialization(object sender, EventArgs args) - { - this.ribbon.Loaded -= this.OnDelayedInitialization; - this.Attach(); - } - - #endregion - - /// - /// Attaches self - /// - public void Attach() - { - if (this.attached) - { - return; - } - - this.attached = true; - - // KeyTip service must not work in design mode - if (DesignerProperties.GetIsInDesignMode(this.ribbon)) - { - return; - } - - this.window = Window.GetWindow(this.ribbon); - if (this.window == null) - { - return; - } - - this.window.PreviewKeyDown += this.OnWindowKeyDown; - this.window.KeyUp += this.OnWindowKeyUp; - - // Hookup non client area messages - this.attachedHwndSource = (HwndSource)PresentationSource.FromVisual(this.window); - if (this.attachedHwndSource != null) - { - this.attachedHwndSource.AddHook(this.WindowProc); - } - } - - /// - /// Detachs self - /// - public void Detach() - { - if (this.attached == false) - { - return; - } - - this.attached = false; - - // prevent delay show - this.timer.Stop(); - - if (this.window != null) - { - this.window.PreviewKeyDown -= this.OnWindowKeyDown; - this.window.KeyUp -= this.OnWindowKeyUp; - - this.window = null; - } - - // Hookup non client area messages - if (this.attachedHwndSource != null - && this.attachedHwndSource.IsDisposed == false) - { - this.attachedHwndSource.RemoveHook(this.WindowProc); - } - } - - // Window's messages hook up - private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - // We must terminate the keytip's adorner chain if: - // - mouse clicks in non client area - // - the window is deactivated - if (((msg >= 161) && (msg <= 173)) || msg == Constants.WM_NCACTIVATE) - { - if (this.activeAdornerChain != null - && this.activeAdornerChain.IsAdornerChainAlive) - { - this.activeAdornerChain.Terminate(); - this.activeAdornerChain = null; - } - } - - return IntPtr.Zero; - } - - private void OnWindowKeyDown(object sender, KeyEventArgs e) - { - if (e.IsRepeat) - { - return; - } - - if (this.ribbon.IsCollapsed) - { - return; - } - - if (IsShowOrHideKey(e)) - { - if (this.activeAdornerChain == null - || this.activeAdornerChain.IsAdornerChainAlive == false - || this.activeAdornerChain.AreAnyKeyTipsVisible == false) - { - this.ShowDelayed(); - } - else if (this.activeAdornerChain != null - && this.activeAdornerChain.IsAdornerChainAlive) - { - // Focus ribbon - this.backUpFocusedElement = Keyboard.FocusedElement; - this.ribbon.Focusable = true; - //this.ribbon.Focus(); - - this.activeAdornerChain.Terminate(); - this.activeAdornerChain = null; - } - else - { - this.ClearUserInput(); - } - } - else if (e.Key == Key.Escape - && this.activeAdornerChain != null) - { - this.activeAdornerChain.ActiveKeyTipAdorner.Back(); - } - else - { - // Should we show the keytips and immediately react to key? - if (e.Key != Key.System - || e.SystemKey == Key.Escape - || e.KeyboardDevice.Modifiers != ModifierKeys.Alt) - { - return; - } - - if (this.activeAdornerChain == null - || this.activeAdornerChain.IsAdornerChainAlive == false - || this.activeAdornerChain.AreAnyKeyTipsVisible == false) - { - this.ShowImmediatly(); - } - - if (this.activeAdornerChain == null) - { - return; - } - - this.currentUserInput += keyConverter.ConvertToString(e.SystemKey); - - if (this.activeAdornerChain.ActiveKeyTipAdorner.Forward(this.currentUserInput, true)) - { - this.ClearUserInput(); - e.Handled = true; - } - } - } - - private void OnWindowKeyUp(object sender, KeyEventArgs e) - { - if (this.ribbon.IsCollapsed) - { - return; - } - - if (IsShowOrHideKey(e)) - { - this.ClearUserInput(); - - e.Handled = true; - - if (this.timer.IsEnabled) - { - this.ShowImmediatly(); - } - } - else - { - this.timer.Stop(); - } - } - - private static bool IsShowOrHideKey(KeyEventArgs e) - { - return e.Key == Key.System - && (e.SystemKey == Key.LeftAlt - || e.SystemKey == Key.RightAlt - || e.SystemKey == Key.F10 - || e.SystemKey == Key.Space); - } - - private void ClearUserInput() - { - this.currentUserInput = string.Empty; - } - - private void RestoreFocuses() - { - if (this.backUpFocusedElement != null) - { - this.backUpFocusedElement.Focus(); - this.backUpFocusedElement = null; // Release the reference, so GC can work - } - - this.ribbon.Focusable = false; - } - - private void OnAdornerChainTerminated(object sender, EventArgs e) - { - this.RestoreFocuses(); - ((KeyTipAdorner)sender).Terminated -= this.OnAdornerChainTerminated; - } - - private void OnDelayedShow(object sender, EventArgs e) - { - if (this.activeAdornerChain == null) - { - this.Show(); - } - - this.timer.Stop(); - } - - private void ShowImmediatly() - { - this.timer.Stop(); - this.backUpFocusedElement = Keyboard.FocusedElement; - - // Focus ribbon - this.ribbon.Focusable = true; - //this.ribbon.Focus(); - - this.Show(); - } - - private void ShowDelayed() - { - if (this.activeAdornerChain != null) - { - this.activeAdornerChain.Terminate(); - } - - this.activeAdornerChain = null; - this.timer.Start(); - } - - private void Show() - { - // Check whether the window is - // - still present (prevents exceptions when window is closed by system commands) - // - still active (prevents keytips showing during Alt-Tab'ing) - if (this.window == null - || this.window.IsActive == false) - { - this.RestoreFocuses(); - return; - } - - this.ClearUserInput(); - - this.activeAdornerChain = new KeyTipAdorner(this.ribbon, this.ribbon, null); - this.activeAdornerChain.Terminated += this.OnAdornerChainTerminated; - - // Special behavior for backstage - var specialControl = this.GetBackstage() - ?? (DependencyObject)this.GetApplicationMenu(); - - if (specialControl != null) - { - this.DirectlyForwardToSpecialControl(specialControl); - } - else - { - this.activeAdornerChain.Attach(); - } - } - - private Backstage GetBackstage() - { - if (this.ribbon.Menu == null) - { - return null; - } - - var control = this.ribbon.Menu as Backstage ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible && obj.IsOpen); - - if (control == null) - { - return null; - } - - return control.IsOpen - ? control - : null; - } - - private ApplicationMenu GetApplicationMenu() - { - if (this.ribbon.Menu == null) - { - return null; - } - - var control = this.ribbon.Menu as ApplicationMenu ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible); - - if (control == null) - { - return null; - } - - return control.IsDropDownOpen - ? control - : null; - } - - private void DirectlyForwardToSpecialControl(DependencyObject specialControl) - { - var keys = KeyTip.GetKeys(specialControl); - if (string.IsNullOrEmpty(keys) == false) - { - this.activeAdornerChain.Forward(KeyTip.GetKeys(specialControl), false); - } - else - { - this.activeAdornerChain.Attach(); - } - } - } +namespace Fluent +{ + using System; + using System.ComponentModel; + using System.Windows; + using System.Windows.Input; + using System.Windows.Interop; + using System.Windows.Threading; + using Fluent.Internal; + using Fluent.Metro.Native; + + /// + /// Handles Alt, F10 and so on + /// + internal class KeyTipService + { + #region Fields + + // Host element, usually this is Ribbon + private readonly Ribbon ribbon; + + // Timer to show KeyTips with delay + private readonly DispatcherTimer timer; + + // Is KeyTips Actived now + private KeyTipAdorner activeAdornerChain; + // This element must be remembered to restore focus + private FocusWrapper backUpFocusedControl; + + // Window where we attached + private Window window; + + // Whether we attached to window + private bool attached; + + // Attached HWND source + private HwndSource attachedHwndSource; + + private string currentUserInput; + + /// + /// Checks if any keytips are visible. + /// + public bool AreAnyKeyTipsVisible + { + get + { + if (this.activeAdornerChain != null) + { + return this.activeAdornerChain.AreAnyKeyTipsVisible; + } + + return false; + } + } + + #endregion + + #region Initialization + + /// + /// Default constrctor + /// + /// Host element + public KeyTipService(Ribbon ribbon) + { + this.ribbon = ribbon; + + if (this.ribbon.IsLoaded == false) + { + this.ribbon.Loaded += this.OnDelayedInitialization; + } + else + { + this.Attach(); + } + + // Initialize timer + this.timer = new DispatcherTimer(TimeSpan.FromSeconds(0.7), DispatcherPriority.SystemIdle, this.OnDelayedShow, Dispatcher.CurrentDispatcher); + this.timer.Stop(); + } + + private void OnDelayedInitialization(object sender, EventArgs args) + { + this.ribbon.Loaded -= this.OnDelayedInitialization; + this.Attach(); + } + + #endregion + + /// + /// Attaches self + /// + public void Attach() + { + if (this.attached) + { + return; + } + + this.attached = true; + + // KeyTip service must not work in design mode + if (DesignerProperties.GetIsInDesignMode(this.ribbon)) + { + return; + } + + this.window = Window.GetWindow(this.ribbon); + if (this.window == null) + { + return; + } + + this.window.PreviewKeyDown += this.OnWindowPreviewKeyDown; + this.window.KeyUp += this.OnWindowKeyUp; + + // Hookup non client area messages + this.attachedHwndSource = (HwndSource)PresentationSource.FromVisual(this.window); + this.attachedHwndSource?.AddHook(this.WindowProc); + } + + /// + /// Detachs self + /// + public void Detach() + { + if (this.attached == false) + { + return; + } + + this.attached = false; + + // prevent delay show + this.timer.Stop(); + + if (this.window != null) + { + this.window.PreviewKeyDown -= this.OnWindowPreviewKeyDown; + this.window.KeyUp -= this.OnWindowKeyUp; + + this.window = null; + } + + // Unhook non client area messages + this.attachedHwndSource?.RemoveHook(this.WindowProc); + } + + // Window's messages hook up + private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + // We must terminate the keytip's adorner chain if: + if (msg == Constants.WM_NCACTIVATE // mouse clicks in non client area + || (msg == Constants.WM_ACTIVATE && wParam == IntPtr.Zero) // the window is deactivated + // >= WM_NCLBUTTONDOWN <= WM_NCXBUTTONDBLCLK + || (msg >= 161 && msg <= 173) // mouse click (non client area) + || (msg >= 513 && msg <= 521) // mouse click + ) + { + if (this.activeAdornerChain != null + && this.activeAdornerChain.IsAdornerChainAlive) + { + this.activeAdornerChain.Terminate(); + } + } + + return IntPtr.Zero; + } + + private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.IsRepeat + || e.Handled) + { + return; + } + + if (this.ribbon.IsCollapsed + || this.ribbon.IsEnabled == false + || this.window.IsActive == false) + { + return; + } + + // Keytips should be cancelled if Alt+Num0 is pressed #241. + // This allows entering special keys via numpad. + if (e.KeyboardDevice.Modifiers == ModifierKeys.Alt + && e.SystemKey >= Key.NumPad0 + && e.SystemKey <= Key.NumPad9) + { + this.activeAdornerChain?.Terminate(); + return; + } + + if (IsShowOrHideKey(e)) + { + if (this.activeAdornerChain == null + || this.activeAdornerChain.IsAdornerChainAlive == false + || this.activeAdornerChain.AreAnyKeyTipsVisible == false) + { + this.ShowDelayed(); + } + else + { + this.activeAdornerChain?.Terminate(); + return; + } + } + else if (e.Key == Key.Escape + && this.activeAdornerChain != null) + { + this.activeAdornerChain.ActiveKeyTipAdorner.Back(); + this.ClearUserInput(); + e.Handled = true; + return; + } + else + { + if ((e.Key != Key.System && this.activeAdornerChain == null) + || e.SystemKey == Key.Escape + || (e.KeyboardDevice.Modifiers != ModifierKeys.Alt && this.activeAdornerChain == null)) + { + return; + } + + var actualKey = e.Key == Key.System ? e.SystemKey : e.Key; + // we need to get the real string input for the key because of keys like ,, #258 + var key = KeyEventUtility.GetStringFromKey(actualKey); + var isKeyRealInput = string.IsNullOrEmpty(key) == false; + + // Don't do anything and let WPF handle the rest + if (isKeyRealInput == false) + { + // This block is a "temporary" fix for keyboard navigation not matching the office behavior. + // If someone finds a way to implement it properly, here is your starting point. + // In office: If you navigate by keyboard (in menus) and keytips are shown they are shown or hidden based on the menu you are in. + // Implementing navigation the way office does would require complex focus/state tracking etc. so i decided to just terminate keytips and not restore focus. + { + this.backUpFocusedControl = null; + this.activeAdornerChain?.Terminate(); + } + return; + } + + var shownImmediately = false; + + // Should we show the keytips and immediately react to key? + if (this.activeAdornerChain == null + || this.activeAdornerChain.IsAdornerChainAlive == false + || this.activeAdornerChain.AreAnyKeyTipsVisible == false) + { + this.ShowImmediatly(); + shownImmediately = true; + } + + if (this.activeAdornerChain == null) + { + return; + } + + var previousInput = this.currentUserInput; + this.currentUserInput += key; + + if (this.activeAdornerChain.ActiveKeyTipAdorner.ContainsKeyTipStartingWith(this.currentUserInput) == false) + { + // Handles access-keys #258 + if (shownImmediately) + { + this.activeAdornerChain?.Terminate(); + return; + } + + // If no key tips match the current input, continue with the previously entered and still correct keys. + this.currentUserInput = previousInput; + System.Media.SystemSounds.Beep.Play(); + e.Handled = true; + return; + } + else if (this.activeAdornerChain.ActiveKeyTipAdorner.Forward(this.currentUserInput, true)) + { + this.ClearUserInput(); + e.Handled = true; + return; + } + else + { + this.activeAdornerChain.ActiveKeyTipAdorner.FilterKeyTips(this.currentUserInput); + e.Handled = true; + return; + } + } + } + + private void OnWindowKeyUp(object sender, KeyEventArgs e) + { + if (this.ribbon.IsCollapsed + || this.ribbon.IsEnabled == false + || this.window.IsActive == false) + { + this.activeAdornerChain?.Terminate(); + return; + } + + if (IsShowOrHideKey(e)) + { + this.ClearUserInput(); + + e.Handled = true; + + if (this.timer.IsEnabled) + { + this.ShowImmediatly(); + } + } + else + { + this.timer.Stop(); + } + } + + private static bool IsShowOrHideKey(KeyEventArgs e) + { + return e.Key == Key.System + && (e.SystemKey == Key.LeftAlt + || e.SystemKey == Key.RightAlt + || e.SystemKey == Key.F10 + || e.SystemKey == Key.Space); + } + + private void ClearUserInput() + { + this.currentUserInput = string.Empty; + } + + private void RestoreFocus() + { + this.backUpFocusedControl?.Focus(); + this.backUpFocusedControl = null; + } + + private void OnAdornerChainTerminated(object sender, EventArgs e) + { + this.activeAdornerChain.Terminated -= this.OnAdornerChainTerminated; + this.activeAdornerChain = null; + this.ClearUserInput(); + this.RestoreFocus(); + } + + private void OnDelayedShow(object sender, EventArgs e) + { + if (this.activeAdornerChain == null) + { + this.Show(); + } + + this.timer.Stop(); + } + + private void ShowImmediatly() + { + this.Show(); + } + + private void ShowDelayed() + { + this.activeAdornerChain?.Terminate(); + + this.timer.Start(); + } + + private void Show() + { + this.timer.Stop(); + + // Check whether the window is + // - still present (prevents exceptions when window is closed by system commands) + // - still active (prevents keytips showing during Alt-Tab'ing) + if (this.window == null + || this.window.IsActive == false) + { + this.RestoreFocus(); + return; + } + + this.backUpFocusedControl = FocusWrapper.GetWrapperForCurrentFocus(); + + // Focus ribbon + this.ribbon.Focus(); + + this.ClearUserInput(); + + this.activeAdornerChain = new KeyTipAdorner(this.ribbon, this.ribbon, null); + this.activeAdornerChain.Terminated += this.OnAdornerChainTerminated; + + // Special behavior for backstage + var specialControl = this.GetBackstage() + ?? this.GetApplicationMenu() + ?? this.GetStartScreen(); + + if (specialControl != null) + { + this.DirectlyForwardToSpecialControl(specialControl); + } + else + { + this.activeAdornerChain.Attach(); + } + } + + private DependencyObject GetBackstage() + { + if (this.ribbon.Menu == null) + { + return null; + } + + var control = this.ribbon.Menu as Backstage ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible); + + if (control == null) + { + return null; + } + + return control.IsOpen + ? control + : null; + } + + private DependencyObject GetApplicationMenu() + { + if (this.ribbon.Menu == null) + { + return null; + } + + var control = this.ribbon.Menu as ApplicationMenu ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible); + + if (control == null) + { + return null; + } + + return control.IsDropDownOpen + ? control + : null; + } + + private DependencyObject GetStartScreen() + { + var control = this.ribbon.StartScreen; + + if (control == null) + { + return null; + } + + return control.IsOpen + ? control + : null; + } + + private void DirectlyForwardToSpecialControl(DependencyObject specialControl) + { + var keys = KeyTip.GetKeys(specialControl); + + if (string.IsNullOrEmpty(keys) == false) + { + this.activeAdornerChain.Forward(keys, false); + } + else + { + this.activeAdornerChain.Attach(); + } + } + } } \ No newline at end of file diff --git a/Fluent/Services/PopupService.cs b/Fluent.Ribbon/Services/PopupService.cs similarity index 97% rename from Fluent/Services/PopupService.cs rename to Fluent.Ribbon/Services/PopupService.cs index da900dee4..73cbefed7 100644 --- a/Fluent/Services/PopupService.cs +++ b/Fluent.Ribbon/Services/PopupService.cs @@ -1,372 +1,372 @@ -namespace Fluent -{ - using System; - using System.Diagnostics; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Input; - using System.Windows.Media; - - /// - /// Dismiss popup mode - /// - public enum DismissPopupMode - { - /// - /// Always dismiss popup - /// - Always, - /// - /// Dismiss only if mouse is not over popup - /// - MouseNotOver - } - - /// - /// Dismiss popup handler - /// - /// - /// - public delegate void DismissPopupEventHandler(object sender, DismissPopupEventArgs e); - - /// - /// Dismiss popup arguments - /// - public class DismissPopupEventArgs : RoutedEventArgs - { - #region Properties - /// - /// Popup dismiss mode - /// - public DismissPopupMode DismissMode { get; set; } - - #endregion - - /// - /// Standard constructor - /// - public DismissPopupEventArgs() - : this(DismissPopupMode.Always) - { - } - - /// - /// Constructor - /// - /// Dismiss mode - public DismissPopupEventArgs(DismissPopupMode dismissMode) - { - this.RoutedEvent = PopupService.DismissPopupEvent; - this.DismissMode = dismissMode; - } - - /// - /// When overridden in a derived class, provides a way to invoke event handlers in a type-specific way, which can increase efficiency over the base implementation. - /// - /// The generic handler / delegate implementation to be invoked.The target on which the provided handler should be invoked. - protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget) - { - var handler = (DismissPopupEventHandler)genericHandler; - handler(genericTarget, this); - } - } - - /// - /// Represent additional popup functionality - /// - public static class PopupService - { - #region DismissPopup - - /// - /// Occurs then popup is dismissed - /// - public static readonly RoutedEvent DismissPopupEvent = EventManager.RegisterRoutedEvent("DismissPopup", RoutingStrategy.Bubble, typeof(DismissPopupEventHandler), typeof(PopupService)); - - /// - /// Raises DismissPopup event (Async) - /// - public static void RaiseDismissPopupEventAsync(object sender, DismissPopupMode mode) - { - var element = sender as UIElement; - - if (element == null) - { - return; - } - - Debug.WriteLine("Dismissing Popup (async)"); - - element.Dispatcher.BeginInvoke((Action)(() => RaiseDismissPopupEvent(sender, mode))); - } - - /// - /// Raises DismissPopup event - /// - public static void RaiseDismissPopupEvent(object sender, DismissPopupMode mode) - { - var element = sender as UIElement; - - if (element == null) - { - return; - } - - Debug.WriteLine("Dismissing Popup"); - - element.RaiseEvent(new DismissPopupEventArgs(mode)); - } - - #endregion - - /// - /// Set needed parameters to control - /// - /// Control type - public static void Attach(Type classType) - { - EventManager.RegisterClassHandler(classType, Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(OnClickThroughThunk)); - EventManager.RegisterClassHandler(classType, DismissPopupEvent, new DismissPopupEventHandler(OnDismissPopup)); - EventManager.RegisterClassHandler(classType, FrameworkElement.ContextMenuOpeningEvent, new ContextMenuEventHandler(OnContextMenuOpened), true); - EventManager.RegisterClassHandler(classType, FrameworkElement.ContextMenuClosingEvent, new ContextMenuEventHandler(OnContextMenuClosed), true); - EventManager.RegisterClassHandler(classType, UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture)); - } - - /// - /// Handles PreviewMouseDownOutsideCapturedElementEvent event - /// - /// - /// - public static void OnClickThroughThunk(object sender, MouseButtonEventArgs e) - { - ////Debug.WriteLine(string.Format("OnClickThroughThunk: sender = {0}; originalSource = {1}; mouse capture = {2}", sender, e.OriginalSource, Mouse.Captured)); - - if (e.ChangedButton == MouseButton.Left - || e.ChangedButton == MouseButton.Right) - { - if (Mouse.Captured == sender - // Special handling for unknown Popups (for example datepickers used in the ribbon) - || (sender is IDropDownControl - && IsPopupRoot(Mouse.Captured) - ) - ) - { - RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); - } - } - } - - /// - /// Handles lost mouse capture event - /// - /// - /// - public static void OnLostMouseCapture(object sender, MouseEventArgs e) - { - Debug.WriteLine(string.Format("Sender - {0}", sender)); - Debug.WriteLine(string.Format("OriginalSource - {0}", e.OriginalSource)); - Debug.WriteLine(string.Format("Mouse.Captured - {0}", Mouse.Captured)); - - var control = sender as IDropDownControl; - - if (control == null) - { - return; - } - - if (Mouse.Captured != sender - && control.IsDropDownOpen - && !control.IsContextMenuOpened) - { - var popup = control.DropDownPopup; - - if (popup == null - || popup.Child == null) - { - RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); - return; - } - - if (e.OriginalSource == sender) - { - // If Ribbon loses capture because something outside popup is clicked - close the popup - if (Mouse.Captured == null - || IsAncestorOf(popup.Child, Mouse.Captured as DependencyObject) == false) - { - RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); - } - - return; - } - - if (IsAncestorOf(popup.Child, e.OriginalSource as DependencyObject) == false) - { - RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); - return; - } - - if (e.OriginalSource != null - && Mouse.Captured == null - && (IsPopupRoot(e.OriginalSource) || IsAncestorOf(popup.Child, e.OriginalSource as DependencyObject))) - { - Debug.WriteLine(string.Format("Setting mouse capture to: {0}", sender)); - Mouse.Capture(sender as IInputElement, CaptureMode.SubTree); - e.Handled = true; - return; - } - } - } - - /// - /// Returns true whether parent is ancestor of element - /// - /// Parent - /// Element - /// Returns true whether parent is ancestor of element - public static bool IsAncestorOf(DependencyObject parent, DependencyObject element) - { - while (element != null) - { - if (ReferenceEquals(element, parent)) - { - return true; - } - - element = VisualTreeHelper.GetParent(element) ?? LogicalTreeHelper.GetParent(element); - } - - return false; - } - - /// - /// Handles dismiss popup event - /// - /// - /// - public static void OnDismissPopup(object sender, DismissPopupEventArgs e) - { - var control = sender as IDropDownControl; - - if (control == null) - { - return; - } - - if (e.DismissMode == DismissPopupMode.Always) - { - if (Mouse.Captured == control) - { - Mouse.Capture(null); - } - - control.IsDropDownOpen = false; - } - else - { - if (control.IsDropDownOpen - && !IsMousePhysicallyOver(control.DropDownPopup)) - { - if (Mouse.Captured == control) - { - Mouse.Capture(null); - } - - control.IsDropDownOpen = false; - } - else - { - if (control.IsDropDownOpen - && Mouse.Captured != control) - { - Mouse.Capture(sender as IInputElement, CaptureMode.SubTree); - } - - if (control.IsDropDownOpen) - { - e.Handled = true; - } - } - } - } - - /// - /// Returns true whether mouse is physically over the popup - /// - /// Element - /// Returns true whether mouse is physically over the popup - public static bool IsMousePhysicallyOver(Popup popup) - { - if (popup == null - || popup.Child == null) - { - return false; - } - - return IsMousePhysicallyOver(popup.Child); - } - - /// - /// Returns true whether mouse is physically over the element - /// - /// Element - /// Returns true whether mouse is physically over the element - public static bool IsMousePhysicallyOver(UIElement element) - { - if (element == null) - { - return false; - } - - var position = Mouse.GetPosition(element); - return ((position.X >= 0.0) && (position.Y >= 0.0)) - && ((position.X <= element.RenderSize.Width) && (position.Y <= element.RenderSize.Height)); - } - - /// - /// Handles context menu opened event - /// - /// - /// - public static void OnContextMenuOpened(object sender, ContextMenuEventArgs e) - { - var control = sender as IDropDownControl; - - if (control != null) - { - control.IsContextMenuOpened = true; - // Debug.WriteLine("Context menu opened"); - } - } - - /// - /// Handles context menu closed event - /// - /// - /// - public static void OnContextMenuClosed(object sender, ContextMenuEventArgs e) - { - var control = sender as IDropDownControl; - - if (control != null) - { - //Debug.WriteLine("Context menu closed"); - control.IsContextMenuOpened = false; - RaiseDismissPopupEvent(control, DismissPopupMode.MouseNotOver); - } - } - - private static bool IsPopupRoot(object obj) - { - if (obj == null) - { - return false; - } - - var type = obj.GetType(); - - return type.FullName == "System.Windows.Controls.Primitives.PopupRoot" - || type.Name == "PopupRoot"; - } - } +namespace Fluent +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Controls.Primitives; + using System.Windows.Input; + using System.Windows.Media; + + /// + /// Dismiss popup mode + /// + public enum DismissPopupMode + { + /// + /// Always dismiss popup + /// + Always, + /// + /// Dismiss only if mouse is not over popup + /// + MouseNotOver + } + + /// + /// Dismiss popup handler + /// + /// + /// + public delegate void DismissPopupEventHandler(object sender, DismissPopupEventArgs e); + + /// + /// Dismiss popup arguments + /// + public class DismissPopupEventArgs : RoutedEventArgs + { + #region Properties + /// + /// Popup dismiss mode + /// + public DismissPopupMode DismissMode { get; set; } + + #endregion + + /// + /// Standard constructor + /// + public DismissPopupEventArgs() + : this(DismissPopupMode.Always) + { + } + + /// + /// Constructor + /// + /// Dismiss mode + public DismissPopupEventArgs(DismissPopupMode dismissMode) + { + this.RoutedEvent = PopupService.DismissPopupEvent; + this.DismissMode = dismissMode; + } + + /// + /// When overridden in a derived class, provides a way to invoke event handlers in a type-specific way, which can increase efficiency over the base implementation. + /// + /// The generic handler / delegate implementation to be invoked.The target on which the provided handler should be invoked. + protected override void InvokeEventHandler(Delegate genericHandler, object genericTarget) + { + var handler = (DismissPopupEventHandler)genericHandler; + handler(genericTarget, this); + } + } + + /// + /// Represent additional popup functionality + /// + public static class PopupService + { + #region DismissPopup + + /// + /// Occurs then popup is dismissed + /// + public static readonly RoutedEvent DismissPopupEvent = EventManager.RegisterRoutedEvent("DismissPopup", RoutingStrategy.Bubble, typeof(DismissPopupEventHandler), typeof(PopupService)); + + /// + /// Raises DismissPopup event (Async) + /// + public static void RaiseDismissPopupEventAsync(object sender, DismissPopupMode mode) + { + var element = sender as UIElement; + + if (element == null) + { + return; + } + + Debug.WriteLine("Dismissing Popup (async)"); + + element.Dispatcher.BeginInvoke((Action)(() => RaiseDismissPopupEvent(sender, mode))); + } + + /// + /// Raises DismissPopup event + /// + public static void RaiseDismissPopupEvent(object sender, DismissPopupMode mode) + { + var element = sender as UIElement; + + if (element == null) + { + return; + } + + Debug.WriteLine("Dismissing Popup"); + + element.RaiseEvent(new DismissPopupEventArgs(mode)); + } + + #endregion + + /// + /// Set needed parameters to control + /// + /// Control type + public static void Attach(Type classType) + { + EventManager.RegisterClassHandler(classType, Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(OnClickThroughThunk)); + EventManager.RegisterClassHandler(classType, DismissPopupEvent, new DismissPopupEventHandler(OnDismissPopup)); + EventManager.RegisterClassHandler(classType, FrameworkElement.ContextMenuOpeningEvent, new ContextMenuEventHandler(OnContextMenuOpened), true); + EventManager.RegisterClassHandler(classType, FrameworkElement.ContextMenuClosingEvent, new ContextMenuEventHandler(OnContextMenuClosed), true); + EventManager.RegisterClassHandler(classType, UIElement.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture)); + } + + /// + /// Handles PreviewMouseDownOutsideCapturedElementEvent event + /// + /// + /// + public static void OnClickThroughThunk(object sender, MouseButtonEventArgs e) + { + ////Debug.WriteLine(string.Format("OnClickThroughThunk: sender = {0}; originalSource = {1}; mouse capture = {2}", sender, e.OriginalSource, Mouse.Captured)); + + if (e.ChangedButton == MouseButton.Left + || e.ChangedButton == MouseButton.Right) + { + if (Mouse.Captured == sender + // Special handling for unknown Popups (for example datepickers used in the ribbon) + || (sender is IDropDownControl + && IsPopupRoot(Mouse.Captured) + ) + ) + { + RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); + } + } + } + + /// + /// Handles lost mouse capture event + /// + /// + /// + public static void OnLostMouseCapture(object sender, MouseEventArgs e) + { + Debug.WriteLine(string.Format("Sender - {0}", sender)); + Debug.WriteLine(string.Format("OriginalSource - {0}", e.OriginalSource)); + Debug.WriteLine(string.Format("Mouse.Captured - {0}", Mouse.Captured)); + + var control = sender as IDropDownControl; + + if (control == null) + { + return; + } + + if (Mouse.Captured != sender + && control.IsDropDownOpen + && !control.IsContextMenuOpened) + { + var popup = control.DropDownPopup; + + if (popup == null + || popup.Child == null) + { + RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); + return; + } + + if (e.OriginalSource == sender) + { + // If Ribbon loses capture because something outside popup is clicked - close the popup + if (Mouse.Captured == null + || IsAncestorOf(popup.Child, Mouse.Captured as DependencyObject) == false) + { + RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); + } + + return; + } + + if (IsAncestorOf(popup.Child, e.OriginalSource as DependencyObject) == false) + { + RaiseDismissPopupEvent(sender, DismissPopupMode.MouseNotOver); + return; + } + + if (e.OriginalSource != null + && Mouse.Captured == null + && (IsPopupRoot(e.OriginalSource) || IsAncestorOf(popup.Child, e.OriginalSource as DependencyObject))) + { + Debug.WriteLine(string.Format("Setting mouse capture to: {0}", sender)); + Mouse.Capture(sender as IInputElement, CaptureMode.SubTree); + e.Handled = true; + return; + } + } + } + + /// + /// Returns true whether parent is ancestor of element + /// + /// Parent + /// Element + /// Returns true whether parent is ancestor of element + public static bool IsAncestorOf(DependencyObject parent, DependencyObject element) + { + while (element != null) + { + if (ReferenceEquals(element, parent)) + { + return true; + } + + element = VisualTreeHelper.GetParent(element) ?? LogicalTreeHelper.GetParent(element); + } + + return false; + } + + /// + /// Handles dismiss popup event + /// + /// + /// + public static void OnDismissPopup(object sender, DismissPopupEventArgs e) + { + var control = sender as IDropDownControl; + + if (control == null) + { + return; + } + + if (e.DismissMode == DismissPopupMode.Always) + { + if (Mouse.Captured == control) + { + Mouse.Capture(null); + } + + control.IsDropDownOpen = false; + } + else + { + if (control.IsDropDownOpen + && !IsMousePhysicallyOver(control.DropDownPopup)) + { + if (Mouse.Captured == control) + { + Mouse.Capture(null); + } + + control.IsDropDownOpen = false; + } + else + { + if (control.IsDropDownOpen + && Mouse.Captured != control) + { + Mouse.Capture(sender as IInputElement, CaptureMode.SubTree); + } + + if (control.IsDropDownOpen) + { + e.Handled = true; + } + } + } + } + + /// + /// Returns true whether mouse is physically over the popup + /// + /// Element + /// Returns true whether mouse is physically over the popup + public static bool IsMousePhysicallyOver(Popup popup) + { + if (popup == null + || popup.Child == null) + { + return false; + } + + return IsMousePhysicallyOver(popup.Child); + } + + /// + /// Returns true whether mouse is physically over the element + /// + /// Element + /// Returns true whether mouse is physically over the element + public static bool IsMousePhysicallyOver(UIElement element) + { + if (element == null) + { + return false; + } + + var position = Mouse.GetPosition(element); + return ((position.X >= 0.0) && (position.Y >= 0.0)) + && ((position.X <= element.RenderSize.Width) && (position.Y <= element.RenderSize.Height)); + } + + /// + /// Handles context menu opened event + /// + /// + /// + public static void OnContextMenuOpened(object sender, ContextMenuEventArgs e) + { + var control = sender as IDropDownControl; + + if (control != null) + { + control.IsContextMenuOpened = true; + // Debug.WriteLine("Context menu opened"); + } + } + + /// + /// Handles context menu closed event + /// + /// + /// + public static void OnContextMenuClosed(object sender, ContextMenuEventArgs e) + { + var control = sender as IDropDownControl; + + if (control != null) + { + //Debug.WriteLine("Context menu closed"); + control.IsContextMenuOpened = false; + RaiseDismissPopupEvent(control, DismissPopupMode.MouseNotOver); + } + } + + private static bool IsPopupRoot(object obj) + { + if (obj == null) + { + return false; + } + + var type = obj.GetType(); + + return type.FullName == "System.Windows.Controls.Primitives.PopupRoot" + || type.Name == "PopupRoot"; + } + } } \ No newline at end of file diff --git a/Fluent/Services/ToolTipService.cs b/Fluent.Ribbon/Services/ToolTipService.cs similarity index 97% rename from Fluent/Services/ToolTipService.cs rename to Fluent.Ribbon/Services/ToolTipService.cs index 4a080d350..3e37f2819 100644 --- a/Fluent/Services/ToolTipService.cs +++ b/Fluent.Ribbon/Services/ToolTipService.cs @@ -1,26 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; - -namespace Fluent -{ - /// - /// Represents additional toltip functionality - /// - public static class ToolTipService - { - /// - /// Attach ooltip properties to control - /// - /// Control type - public static void Attach(Type type) - { - System.Windows.Controls.ToolTipService.ShowOnDisabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(true)); - System.Windows.Controls.ToolTipService.InitialShowDelayProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(900)); - System.Windows.Controls.ToolTipService.BetweenShowDelayProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(0)); - System.Windows.Controls.ToolTipService.ShowDurationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(20000)); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; + +namespace Fluent +{ + /// + /// Represents additional toltip functionality + /// + public static class ToolTipService + { + /// + /// Attach ooltip properties to control + /// + /// Control type + public static void Attach(Type type) + { + System.Windows.Controls.ToolTipService.ShowOnDisabledProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(true)); + System.Windows.Controls.ToolTipService.InitialShowDelayProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(900)); + System.Windows.Controls.ToolTipService.BetweenShowDelayProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(0)); + System.Windows.Controls.ToolTipService.ShowDurationProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(20000)); + } + } +} diff --git a/Fluent/Themes/Generic.xaml b/Fluent.Ribbon/Themes/Generic.xaml similarity index 100% rename from Fluent/Themes/Generic.xaml rename to Fluent.Ribbon/Themes/Generic.xaml diff --git a/Fluent/Themes/Generic/Common.xaml b/Fluent.Ribbon/Themes/Generic/Common.xaml similarity index 92% rename from Fluent/Themes/Generic/Common.xaml rename to Fluent.Ribbon/Themes/Generic/Common.xaml index 6b2cd4873..d0cf90ad8 100644 --- a/Fluent/Themes/Generic/Common.xaml +++ b/Fluent.Ribbon/Themes/Generic/Common.xaml @@ -23,7 +23,12 @@ BasedOn="{StaticResource BackstageStyle}" /> + \ No newline at end of file diff --git a/Fluent/Themes/Generic/Controls/EmptyFocusStyle.xaml b/Fluent.Ribbon/Themes/Generic/Controls/EmptyFocusStyle.xaml similarity index 100% rename from Fluent/Themes/Generic/Controls/EmptyFocusStyle.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/EmptyFocusStyle.xaml diff --git a/Fluent/Themes/Generic/Controls/GalleryGroupContainer.xaml b/Fluent.Ribbon/Themes/Generic/Controls/GalleryGroupContainer.xaml similarity index 100% rename from Fluent/Themes/Generic/Controls/GalleryGroupContainer.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/GalleryGroupContainer.xaml diff --git a/Fluent/Themes/Generic/Controls/MenuSeparator.xaml b/Fluent.Ribbon/Themes/Generic/Controls/MenuSeparator.xaml similarity index 100% rename from Fluent/Themes/Generic/Controls/MenuSeparator.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/MenuSeparator.xaml diff --git a/Fluent/Themes/Generic/Controls/RadioButton.xaml b/Fluent.Ribbon/Themes/Generic/Controls/RadioButton.xaml similarity index 100% rename from Fluent/Themes/Generic/Controls/RadioButton.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/RadioButton.xaml diff --git a/Fluent/Themes/Generic/Controls/RibbonMenu.xaml b/Fluent.Ribbon/Themes/Generic/Controls/RibbonMenu.xaml similarity index 100% rename from Fluent/Themes/Generic/Controls/RibbonMenu.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/RibbonMenu.xaml diff --git a/Fluent/Themes/Generic/Controls/RibbonScrollViewer.xaml b/Fluent.Ribbon/Themes/Generic/Controls/RibbonScrollViewer.xaml similarity index 99% rename from Fluent/Themes/Generic/Controls/RibbonScrollViewer.xaml rename to Fluent.Ribbon/Themes/Generic/Controls/RibbonScrollViewer.xaml index 632c86e6f..69b319e28 100644 --- a/Fluent/Themes/Generic/Controls/RibbonScrollViewer.xaml +++ b/Fluent.Ribbon/Themes/Generic/Controls/RibbonScrollViewer.xaml @@ -64,7 +64,7 @@ - + - + - + - + - + - + + xmlns:Fluent="clr-namespace:Fluent" + xmlns:Converters="clr-namespace:Fluent.Converters"> + \ No newline at end of file diff --git a/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControlTemplate.xaml b/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControlTemplate.xaml new file mode 100644 index 000000000..64533bdfc --- /dev/null +++ b/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControlTemplate.xaml @@ -0,0 +1,68 @@ + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Black.xaml b/Fluent.Ribbon/Themes/Office2010/Black.xaml similarity index 98% rename from Fluent/Themes/Office2010/Black.xaml rename to Fluent.Ribbon/Themes/Office2010/Black.xaml index 17324face..11fba7796 100644 --- a/Fluent/Themes/Office2010/Black.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Black.xaml @@ -1,6 +1,6 @@ - - - - + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Blue.xaml b/Fluent.Ribbon/Themes/Office2010/Blue.xaml similarity index 98% rename from Fluent/Themes/Office2010/Blue.xaml rename to Fluent.Ribbon/Themes/Office2010/Blue.xaml index 058c167b8..b03d57609 100644 --- a/Fluent/Themes/Office2010/Blue.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Blue.xaml @@ -1,6 +1,6 @@ - - - - + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Colors/Colors.xaml b/Fluent.Ribbon/Themes/Office2010/Colors/Colors.xaml similarity index 97% rename from Fluent/Themes/Office2010/Colors/Colors.xaml rename to Fluent.Ribbon/Themes/Office2010/Colors/Colors.xaml index e1f554b2e..d4df2e0ce 100644 --- a/Fluent/Themes/Office2010/Colors/Colors.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Colors/Colors.xaml @@ -1,399 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Colors/ColorsBlack.xaml b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlack.xaml similarity index 97% rename from Fluent/Themes/Office2010/Colors/ColorsBlack.xaml rename to Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlack.xaml index 17e4ddca7..8ad5cccac 100644 --- a/Fluent/Themes/Office2010/Colors/ColorsBlack.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlack.xaml @@ -1,487 +1,487 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #D8484848 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D8484848 + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Colors/ColorsBlue.xaml b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlue.xaml similarity index 97% rename from Fluent/Themes/Office2010/Colors/ColorsBlue.xaml rename to Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlue.xaml index 86f874f4c..6c2e25243 100644 --- a/Fluent/Themes/Office2010/Colors/ColorsBlue.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsBlue.xaml @@ -1,484 +1,484 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #D8F9F7FA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D8F9F7FA \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Colors/ColorsSilver.xaml b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsSilver.xaml similarity index 97% rename from Fluent/Themes/Office2010/Colors/ColorsSilver.xaml rename to Fluent.Ribbon/Themes/Office2010/Colors/ColorsSilver.xaml index fc1096691..8bfbb1ec7 100644 --- a/Fluent/Themes/Office2010/Colors/ColorsSilver.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Colors/ColorsSilver.xaml @@ -1,475 +1,475 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #D8FFFFFF - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #D8FFFFFF + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ApplicationMenu.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml similarity index 90% rename from Fluent/Themes/Office2010/Controls/ApplicationMenu.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml index c8a86b2db..9d7669b5e 100644 --- a/Fluent/Themes/Office2010/Controls/ApplicationMenu.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml @@ -1,402 +1,391 @@ - - - - - - - - - - + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ApplicationMenuItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml similarity index 96% rename from Fluent/Themes/Office2010/Controls/ApplicationMenuItem.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml index 2303a7abb..fa3a9a0ea 100644 --- a/Fluent/Themes/Office2010/Controls/ApplicationMenuItem.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml @@ -1,1715 +1,1730 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Backstage.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Backstage.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/Backstage.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Backstage.xaml index 7d2c195e7..ba68337de 100644 --- a/Fluent/Themes/Office2010/Controls/Backstage.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Backstage.xaml @@ -1,295 +1,295 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/BackstageControls.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageControls.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/BackstageControls.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/BackstageControls.xaml index 045f23476..0c1173729 100644 --- a/Fluent/Themes/Office2010/Controls/BackstageControls.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageControls.xaml @@ -1,1578 +1,1578 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/BackstageTabControl.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabControl.xaml similarity index 94% rename from Fluent/Themes/Office2010/Controls/BackstageTabControl.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabControl.xaml index b53c34507..98db29c83 100644 --- a/Fluent/Themes/Office2010/Controls/BackstageTabControl.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabControl.xaml @@ -1,284 +1,284 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/BackstageTabItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabItem.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/BackstageTabItem.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabItem.xaml index f77c837fc..9b449520c 100644 --- a/Fluent/Themes/Office2010/Controls/BackstageTabItem.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/BackstageTabItem.xaml @@ -1,128 +1,128 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Button.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Button.xaml similarity index 93% rename from Fluent/Themes/Office2010/Controls/Button.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Button.xaml index d7391b65c..9a843bbef 100644 --- a/Fluent/Themes/Office2010/Controls/Button.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Button.xaml @@ -1,226 +1,227 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/CheckBox.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/CheckBox.xaml similarity index 93% rename from Fluent/Themes/Office2010/Controls/CheckBox.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/CheckBox.xaml index c86f83f4e..95a507c12 100644 --- a/Fluent/Themes/Office2010/Controls/CheckBox.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/CheckBox.xaml @@ -1,190 +1,199 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ComboBox.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ComboBox.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/ComboBox.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ComboBox.xaml index c39d92c58..a893c7457 100644 --- a/Fluent/Themes/Office2010/Controls/ComboBox.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ComboBox.xaml @@ -1,673 +1,674 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ComboBoxItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ComboBoxItem.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/ComboBoxItem.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ComboBoxItem.xaml index 85979a5ba..41dcd8fc1 100644 --- a/Fluent/Themes/Office2010/Controls/ComboBoxItem.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ComboBoxItem.xaml @@ -1,124 +1,124 @@ - - - - + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/DropDownButton.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/DropDownButton.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/DropDownButton.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/DropDownButton.xaml index d50580131..df2e5a5ac 100644 --- a/Fluent/Themes/Office2010/Controls/DropDownButton.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/DropDownButton.xaml @@ -1,357 +1,357 @@ - - - - - - - - - + + + - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/GalleryItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/GalleryItem.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/GalleryItem.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/GalleryItem.xaml index e6c83b272..8e2ac10f4 100644 --- a/Fluent/Themes/Office2010/Controls/GalleryItem.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/GalleryItem.xaml @@ -1,88 +1,88 @@ - - + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/InRibbonGallery.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/InRibbonGallery.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/InRibbonGallery.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/InRibbonGallery.xaml index 3b9ae2abc..989cbff3b 100644 --- a/Fluent/Themes/Office2010/Controls/InRibbonGallery.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/InRibbonGallery.xaml @@ -1,712 +1,715 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/KeyTip.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/KeyTip.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/KeyTip.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/KeyTip.xaml index 43c32f4c3..e9e7626c3 100644 --- a/Fluent/Themes/Office2010/Controls/KeyTip.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/KeyTip.xaml @@ -1,39 +1,39 @@ - - - + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Menu.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Menu.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/Menu.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Menu.xaml index 50842639c..4f255ec4e 100644 --- a/Fluent/Themes/Office2010/Controls/Menu.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Menu.xaml @@ -1,236 +1,236 @@ - - - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Ribbon.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Ribbon.xaml similarity index 92% rename from Fluent/Themes/Office2010/Controls/Ribbon.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Ribbon.xaml index 3a3f5739c..6fc594655 100644 --- a/Fluent/Themes/Office2010/Controls/Ribbon.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Ribbon.xaml @@ -1,141 +1,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml index b28c1a673..37ebfcc17 100644 --- a/Fluent/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonContextualTabGroup.xaml @@ -1,123 +1,123 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/RibbonGroupBox.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonGroupBox.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/RibbonGroupBox.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/RibbonGroupBox.xaml index a3490b3a3..42d1a5b89 100644 --- a/Fluent/Themes/Office2010/Controls/RibbonGroupBox.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonGroupBox.xaml @@ -1,815 +1,816 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/RibbonStatusBar.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonStatusBar.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/RibbonStatusBar.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/RibbonStatusBar.xaml index dc17dce0f..72d51ae0e 100644 --- a/Fluent/Themes/Office2010/Controls/RibbonStatusBar.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonStatusBar.xaml @@ -1,221 +1,221 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/RibbonTabItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonTabItem.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/RibbonTabItem.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/RibbonTabItem.xaml index c3c159694..aac51c2a0 100644 --- a/Fluent/Themes/Office2010/Controls/RibbonTabItem.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/RibbonTabItem.xaml @@ -1,518 +1,518 @@ - - + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ScreenTip.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ScreenTip.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/ScreenTip.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ScreenTip.xaml index 35d15e42a..aebe75cc7 100644 --- a/Fluent/Themes/Office2010/Controls/ScreenTip.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ScreenTip.xaml @@ -1,447 +1,447 @@ - - - - + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ScrollBar.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ScrollBar.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/ScrollBar.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ScrollBar.xaml index 1283b26bc..47bc8001c 100644 --- a/Fluent/Themes/Office2010/Controls/ScrollBar.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ScrollBar.xaml @@ -1,637 +1,637 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ScrollBarWhite.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ScrollBarWhite.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/ScrollBarWhite.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ScrollBarWhite.xaml index 2fa80d463..420d720d2 100644 --- a/Fluent/Themes/Office2010/Controls/ScrollBarWhite.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ScrollBarWhite.xaml @@ -1,576 +1,576 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Slider.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Slider.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/Slider.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Slider.xaml index bf802f094..b3fee1304 100644 --- a/Fluent/Themes/Office2010/Controls/Slider.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Slider.xaml @@ -1,344 +1,344 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/Spinner.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/Spinner.xaml similarity index 98% rename from Fluent/Themes/Office2010/Controls/Spinner.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/Spinner.xaml index 3b67c1f6c..9611d06ae 100644 --- a/Fluent/Themes/Office2010/Controls/Spinner.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/Spinner.xaml @@ -1,311 +1,311 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/SplitButton.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/SplitButton.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/SplitButton.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/SplitButton.xaml index 688e053b4..8efe1d9ec 100644 --- a/Fluent/Themes/Office2010/Controls/SplitButton.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/SplitButton.xaml @@ -1,739 +1,736 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon/Themes/Office2010/Controls/StartScreenTabControl.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/StartScreenTabControl.xaml new file mode 100644 index 000000000..19ff3aa1b --- /dev/null +++ b/Fluent.Ribbon/Themes/Office2010/Controls/StartScreenTabControl.xaml @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/StatusBar.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/StatusBar.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/StatusBar.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/StatusBar.xaml index 9703e20b0..d1540e1ab 100644 --- a/Fluent/Themes/Office2010/Controls/StatusBar.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/StatusBar.xaml @@ -1,66 +1,66 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Controls/ToggleButton.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ToggleButton.xaml similarity index 97% rename from Fluent/Themes/Office2010/Controls/ToggleButton.xaml rename to Fluent.Ribbon/Themes/Office2010/Controls/ToggleButton.xaml index 76644bc6c..318346006 100644 --- a/Fluent/Themes/Office2010/Controls/ToggleButton.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Controls/ToggleButton.xaml @@ -1,246 +1,247 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Effects/Grayscale.fx b/Fluent.Ribbon/Themes/Office2010/Effects/Grayscale.fx similarity index 97% rename from Fluent/Themes/Office2010/Effects/Grayscale.fx rename to Fluent.Ribbon/Themes/Office2010/Effects/Grayscale.fx index ba5be3acb..35f75308a 100644 --- a/Fluent/Themes/Office2010/Effects/Grayscale.fx +++ b/Fluent.Ribbon/Themes/Office2010/Effects/Grayscale.fx @@ -1,31 +1,31 @@ -/// MonochromeEffect -/// Shazzam.Shaders -/// An effect that turns the input into shades of a single color. - -//----------------------------------------------------------------------------------------- -// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.) -//----------------------------------------------------------------------------------------- - -/// The color used to tint the input. -/// Yellow -float4 FilterColor : register(C0); - -//-------------------------------------------------------------------------------------- -// Sampler Inputs (Brushes, including ImplicitInput) -//-------------------------------------------------------------------------------------- - -sampler2D implicitInputSampler : register(S0); - -//-------------------------------------------------------------------------------------- -// Pixel Shader -//-------------------------------------------------------------------------------------- - -float4 main(float2 uv : TEXCOORD) : COLOR -{ - float4 srcColor = tex2D(implicitInputSampler, uv); - float3 rgb = srcColor.rgb; - float3 luminance = dot(rgb, float3(0.30, 0.59, 0.11)); - return float4(luminance * FilterColor.rgb, srcColor.a); -} - - +/// MonochromeEffect +/// Shazzam.Shaders +/// An effect that turns the input into shades of a single color. + +//----------------------------------------------------------------------------------------- +// Shader constant register mappings (scalars - float, double, Point, Color, Point3D, etc.) +//----------------------------------------------------------------------------------------- + +/// The color used to tint the input. +/// Yellow +float4 FilterColor : register(C0); + +//-------------------------------------------------------------------------------------- +// Sampler Inputs (Brushes, including ImplicitInput) +//-------------------------------------------------------------------------------------- + +sampler2D implicitInputSampler : register(S0); + +//-------------------------------------------------------------------------------------- +// Pixel Shader +//-------------------------------------------------------------------------------------- + +float4 main(float2 uv : TEXCOORD) : COLOR +{ + float4 srcColor = tex2D(implicitInputSampler, uv); + float3 rgb = srcColor.rgb; + float3 luminance = dot(rgb, float3(0.30, 0.59, 0.11)); + return float4(luminance * FilterColor.rgb, srcColor.a); +} + + diff --git a/Fluent/Themes/Office2010/Effects/Grayscale.ps b/Fluent.Ribbon/Themes/Office2010/Effects/Grayscale.ps similarity index 100% rename from Fluent/Themes/Office2010/Effects/Grayscale.ps rename to Fluent.Ribbon/Themes/Office2010/Effects/Grayscale.ps diff --git a/Fluent/Themes/Office2010/Generic.txt b/Fluent.Ribbon/Themes/Office2010/Generic.txt similarity index 93% rename from Fluent/Themes/Office2010/Generic.txt rename to Fluent.Ribbon/Themes/Office2010/Generic.txt index 13ccc4298..7a4b291d6 100644 --- a/Fluent/Themes/Office2010/Generic.txt +++ b/Fluent.Ribbon/Themes/Office2010/Generic.txt @@ -33,6 +33,9 @@ Office2010\Controls\InRibbonGallery.xaml Office2010\Controls\BackstageTabItem.xaml Office2010\Controls\BackstageControls.xaml Office2010\Controls\BackstageTabControl.xaml +Generic\Controls\StartScreen.xaml +Generic\Controls\StartScreenTabControlTemplate.xaml +Office2010\Controls\StartScreenTabControl.xaml Office2010\Controls\RibbonSeparator.xaml Generic\Controls\RibbonToolBar.xaml Generic\Controls\RibbonToolBarControlGroup.xaml diff --git a/Fluent/Themes/Office2010/Images/ApplicationMenu.png b/Fluent.Ribbon/Themes/Office2010/Images/ApplicationMenu.png similarity index 100% rename from Fluent/Themes/Office2010/Images/ApplicationMenu.png rename to Fluent.Ribbon/Themes/Office2010/Images/ApplicationMenu.png diff --git a/Fluent/Themes/Office2010/Images/BackstageCorner.png b/Fluent.Ribbon/Themes/Office2010/Images/BackstageCorner.png similarity index 100% rename from Fluent/Themes/Office2010/Images/BackstageCorner.png rename to Fluent.Ribbon/Themes/Office2010/Images/BackstageCorner.png diff --git a/Fluent/Themes/Office2010/Images/CaptionButtonClose.png b/Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonClose.png similarity index 100% rename from Fluent/Themes/Office2010/Images/CaptionButtonClose.png rename to Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonClose.png diff --git a/Fluent/Themes/Office2010/Images/CaptionButtonMaximize.png b/Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonMaximize.png similarity index 100% rename from Fluent/Themes/Office2010/Images/CaptionButtonMaximize.png rename to Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonMaximize.png diff --git a/Fluent/Themes/Office2010/Images/CaptionButtonMinimize.png b/Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonMinimize.png similarity index 100% rename from Fluent/Themes/Office2010/Images/CaptionButtonMinimize.png rename to Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonMinimize.png diff --git a/Fluent/Themes/Office2010/Images/CaptionButtonNormalize.png b/Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonNormalize.png similarity index 100% rename from Fluent/Themes/Office2010/Images/CaptionButtonNormalize.png rename to Fluent.Ribbon/Themes/Office2010/Images/CaptionButtonNormalize.png diff --git a/Fluent/Themes/Office2010/Images/Checked.png b/Fluent.Ribbon/Themes/Office2010/Images/Checked.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Checked.png rename to Fluent.Ribbon/Themes/Office2010/Images/Checked.png diff --git a/Fluent/Themes/Office2010/Images/Copy.png b/Fluent.Ribbon/Themes/Office2010/Images/Copy.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Copy.png rename to Fluent.Ribbon/Themes/Office2010/Images/Copy.png diff --git a/Fluent/Themes/Office2010/Images/Cut.png b/Fluent.Ribbon/Themes/Office2010/Images/Cut.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Cut.png rename to Fluent.Ribbon/Themes/Office2010/Images/Cut.png diff --git a/Fluent/Themes/Office2010/Images/DialogLauncher.png b/Fluent.Ribbon/Themes/Office2010/Images/DialogLauncher.png similarity index 100% rename from Fluent/Themes/Office2010/Images/DialogLauncher.png rename to Fluent.Ribbon/Themes/Office2010/Images/DialogLauncher.png diff --git a/Fluent/Themes/Office2010/Images/Help.png b/Fluent.Ribbon/Themes/Office2010/Images/Help.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Help.png rename to Fluent.Ribbon/Themes/Office2010/Images/Help.png diff --git a/Fluent/Themes/Office2010/Images/Images.xaml b/Fluent.Ribbon/Themes/Office2010/Images/Images.xaml similarity index 98% rename from Fluent/Themes/Office2010/Images/Images.xaml rename to Fluent.Ribbon/Themes/Office2010/Images/Images.xaml index c89a3fc9e..be0fe5a10 100644 --- a/Fluent/Themes/Office2010/Images/Images.xaml +++ b/Fluent.Ribbon/Themes/Office2010/Images/Images.xaml @@ -1,29 +1,29 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2010/Images/MoreColors.png b/Fluent.Ribbon/Themes/Office2010/Images/MoreColors.png similarity index 100% rename from Fluent/Themes/Office2010/Images/MoreColors.png rename to Fluent.Ribbon/Themes/Office2010/Images/MoreColors.png diff --git a/Fluent/Themes/Office2010/Images/Paste.png b/Fluent.Ribbon/Themes/Office2010/Images/Paste.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Paste.png rename to Fluent.Ribbon/Themes/Office2010/Images/Paste.png diff --git a/Fluent/Themes/Office2010/Images/QuickAccessToolbarDropDown.png b/Fluent.Ribbon/Themes/Office2010/Images/QuickAccessToolbarDropDown.png similarity index 100% rename from Fluent/Themes/Office2010/Images/QuickAccessToolbarDropDown.png rename to Fluent.Ribbon/Themes/Office2010/Images/QuickAccessToolbarDropDown.png diff --git a/Fluent/Themes/Office2010/Images/QuickAccessToolbarExtender.png b/Fluent.Ribbon/Themes/Office2010/Images/QuickAccessToolbarExtender.png similarity index 100% rename from Fluent/Themes/Office2010/Images/QuickAccessToolbarExtender.png rename to Fluent.Ribbon/Themes/Office2010/Images/QuickAccessToolbarExtender.png diff --git a/Fluent/Themes/Office2010/Images/ResizeGrip.png b/Fluent.Ribbon/Themes/Office2010/Images/ResizeGrip.png similarity index 100% rename from Fluent/Themes/Office2010/Images/ResizeGrip.png rename to Fluent.Ribbon/Themes/Office2010/Images/ResizeGrip.png diff --git a/Fluent/Themes/Office2010/Images/RibbonCollapse.png b/Fluent.Ribbon/Themes/Office2010/Images/RibbonCollapse.png similarity index 100% rename from Fluent/Themes/Office2010/Images/RibbonCollapse.png rename to Fluent.Ribbon/Themes/Office2010/Images/RibbonCollapse.png diff --git a/Fluent/Themes/Office2010/Images/RibbonExpand.png b/Fluent.Ribbon/Themes/Office2010/Images/RibbonExpand.png similarity index 100% rename from Fluent/Themes/Office2010/Images/RibbonExpand.png rename to Fluent.Ribbon/Themes/Office2010/Images/RibbonExpand.png diff --git a/Fluent/Themes/Office2010/Images/RibbonPin.png b/Fluent.Ribbon/Themes/Office2010/Images/RibbonPin.png similarity index 100% rename from Fluent/Themes/Office2010/Images/RibbonPin.png rename to Fluent.Ribbon/Themes/Office2010/Images/RibbonPin.png diff --git a/Fluent/Themes/Office2010/Images/Warning.png b/Fluent.Ribbon/Themes/Office2010/Images/Warning.png similarity index 100% rename from Fluent/Themes/Office2010/Images/Warning.png rename to Fluent.Ribbon/Themes/Office2010/Images/Warning.png diff --git a/Fluent/Themes/Windows8/RibbonWindow.xaml b/Fluent.Ribbon/Themes/Office2010/RibbonWindow.xaml similarity index 76% rename from Fluent/Themes/Windows8/RibbonWindow.xaml rename to Fluent.Ribbon/Themes/Office2010/RibbonWindow.xaml index bcbe83aef..7a7e38ee5 100644 --- a/Fluent/Themes/Windows8/RibbonWindow.xaml +++ b/Fluent.Ribbon/Themes/Office2010/RibbonWindow.xaml @@ -6,7 +6,7 @@ xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" xmlns:System="clr-namespace:System;assembly=mscorlib" xmlns:Fluent="clr-namespace:Fluent" - xmlns:Behaviours="clr-namespace:Fluent.Metro.Behaviours"> + xmlns:Converters="clr-namespace:Fluent.Converters"> - + - - - - + + + + + + + - - + Margin="4,4,0,0" + Visibility="{TemplateBinding IsIconVisible, Converter={StaticResource BooleanToVisibilityConverter}}" + Source="{TemplateBinding Icon, Converter={StaticResource IconConvert}}" + SnapsToDevicePixels="True" /> + + + + + TargetName="rectangle" + Value="15,4,0,1" /> - + TargetName="rectangle1" + Value="0,4,15.1,1" /> + + - - - - + + + - - - + CornerRadius="7,7,7,7" + Background="{x:Null}" + Opacity="1"> + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - - - + + @@ -450,13 +460,6 @@ Value="1" /> - - - - - @@ -611,10 +614,10 @@ + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Backstage.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Backstage.xaml similarity index 90% rename from Fluent/Themes/Office2013/Controls/Backstage.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Backstage.xaml index 2433e34c0..bf3d7ac98 100644 --- a/Fluent/Themes/Office2013/Controls/Backstage.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Backstage.xaml @@ -1,87 +1,96 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/BackstageControls.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageControls.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/BackstageControls.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/BackstageControls.xaml index bff2cddfc..fb7536106 100644 --- a/Fluent/Themes/Office2013/Controls/BackstageControls.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageControls.xaml @@ -1,1288 +1,1286 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/BackstageTabControl.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml similarity index 88% rename from Fluent/Themes/Office2013/Controls/BackstageTabControl.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml index 37772f1af..c8fa59525 100644 --- a/Fluent/Themes/Office2013/Controls/BackstageTabControl.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml @@ -1,286 +1,294 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/BackstageTabItem.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabItem.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/BackstageTabItem.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabItem.xaml index 14edba809..17da951ed 100644 --- a/Fluent/Themes/Office2013/Controls/BackstageTabItem.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabItem.xaml @@ -1,89 +1,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Button.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml similarity index 59% rename from Fluent/Themes/Office2013/Controls/Button.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml index b2a6dccb6..767138c14 100644 --- a/Fluent/Themes/Office2013/Controls/Button.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml @@ -1,249 +1,191 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/CheckBox.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/CheckBox.xaml similarity index 96% rename from Fluent/Themes/Office2013/Controls/CheckBox.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/CheckBox.xaml index 2851b3208..91295899d 100644 --- a/Fluent/Themes/Office2013/Controls/CheckBox.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/CheckBox.xaml @@ -1,241 +1,251 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Visible - - - - - - - - - - - Visible - - - - - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/ComboBoxItem.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/ComboBoxItem.xaml similarity index 98% rename from Fluent/Themes/Office2013/Controls/ComboBoxItem.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/ComboBoxItem.xaml index d82fcfa77..bb3ba9948 100644 --- a/Fluent/Themes/Office2013/Controls/ComboBoxItem.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/ComboBoxItem.xaml @@ -1,134 +1,134 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/DropDownButton.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/DropDownButton.xaml similarity index 96% rename from Fluent/Themes/Office2013/Controls/DropDownButton.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/DropDownButton.xaml index 85453b738..b98027e03 100644 --- a/Fluent/Themes/Office2013/Controls/DropDownButton.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/DropDownButton.xaml @@ -1,304 +1,304 @@ - - - - - + + + - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/GalleryItem.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/GalleryItem.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/GalleryItem.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/GalleryItem.xaml index 905aacbab..e23017fb0 100644 --- a/Fluent/Themes/Office2013/Controls/GalleryItem.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/GalleryItem.xaml @@ -1,71 +1,71 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/InRibbonGallery.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/InRibbonGallery.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml index 59cbb7985..6de6f1405 100644 --- a/Fluent/Themes/Office2013/Controls/InRibbonGallery.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml @@ -1,657 +1,660 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/KeyTip.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/KeyTip.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/KeyTip.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/KeyTip.xaml index 4b359decf..63303cbc2 100644 --- a/Fluent/Themes/Office2013/Controls/KeyTip.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/KeyTip.xaml @@ -1,36 +1,36 @@ - - - + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Menu.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Menu.xaml similarity index 98% rename from Fluent/Themes/Office2013/Controls/Menu.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Menu.xaml index e0d9798b9..b768d0563 100644 --- a/Fluent/Themes/Office2013/Controls/Menu.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Menu.xaml @@ -1,209 +1,209 @@ - - - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Ribbon.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Ribbon.xaml similarity index 90% rename from Fluent/Themes/Office2013/Controls/Ribbon.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Ribbon.xaml index 5b8062965..db2347f0b 100644 --- a/Fluent/Themes/Office2013/Controls/Ribbon.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Ribbon.xaml @@ -1,120 +1,129 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Fluent/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml index 6018339f2..d8fba900d 100644 --- a/Fluent/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonContextualTabGroup.xaml @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/RibbonGroupBox.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonGroupBox.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/RibbonGroupBox.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/RibbonGroupBox.xaml index bddf4cdf7..fcce7a164 100644 --- a/Fluent/Themes/Office2013/Controls/RibbonGroupBox.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonGroupBox.xaml @@ -1,795 +1,796 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/RibbonStatusBar.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonStatusBar.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/RibbonStatusBar.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/RibbonStatusBar.xaml index 72a448566..7cd6e224a 100644 --- a/Fluent/Themes/Office2013/Controls/RibbonStatusBar.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonStatusBar.xaml @@ -1,208 +1,212 @@ - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/RibbonTabItem.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonTabItem.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/RibbonTabItem.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/RibbonTabItem.xaml index 6dc6ab177..2b7d174e3 100644 --- a/Fluent/Themes/Office2013/Controls/RibbonTabItem.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/RibbonTabItem.xaml @@ -1,349 +1,349 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/ScreenTip.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/ScreenTip.xaml similarity index 98% rename from Fluent/Themes/Office2013/Controls/ScreenTip.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/ScreenTip.xaml index 9f766168f..56857206a 100644 --- a/Fluent/Themes/Office2013/Controls/ScreenTip.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/ScreenTip.xaml @@ -1,238 +1,238 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/ScrollBar.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/ScrollBar.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/ScrollBar.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/ScrollBar.xaml index a187cd4e3..3325585b7 100644 --- a/Fluent/Themes/Office2013/Controls/ScrollBar.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/ScrollBar.xaml @@ -1,462 +1,462 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 36 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 36 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Slider.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Slider.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/Slider.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Slider.xaml index 88b112b0c..800615eed 100644 --- a/Fluent/Themes/Office2013/Controls/Slider.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Slider.xaml @@ -1,264 +1,264 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/Spinner.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Spinner.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/Spinner.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/Spinner.xaml index 64866247a..a65a5be87 100644 --- a/Fluent/Themes/Office2013/Controls/Spinner.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/Spinner.xaml @@ -1,273 +1,273 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/SplitButton.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/SplitButton.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/SplitButton.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/SplitButton.xaml index d6c237e54..0a9713f96 100644 --- a/Fluent/Themes/Office2013/Controls/SplitButton.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/SplitButton.xaml @@ -1,470 +1,471 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon/Themes/Office2013/Controls/StartScreenTabControl.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/StartScreenTabControl.xaml new file mode 100644 index 000000000..47ec03104 --- /dev/null +++ b/Fluent.Ribbon/Themes/Office2013/Controls/StartScreenTabControl.xaml @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/StatusBar.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/StatusBar.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/StatusBar.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/StatusBar.xaml index 90bcfa6bd..ffe8480fb 100644 --- a/Fluent/Themes/Office2013/Controls/StatusBar.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/StatusBar.xaml @@ -1,63 +1,63 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Controls/ToggleButton.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/ToggleButton.xaml similarity index 97% rename from Fluent/Themes/Office2013/Controls/ToggleButton.xaml rename to Fluent.Ribbon/Themes/Office2013/Controls/ToggleButton.xaml index c733a67fd..ec4f613eb 100644 --- a/Fluent/Themes/Office2013/Controls/ToggleButton.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Controls/ToggleButton.xaml @@ -1,204 +1,208 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Generic.txt b/Fluent.Ribbon/Themes/Office2013/Generic.txt similarity index 90% rename from Fluent/Themes/Office2013/Generic.txt rename to Fluent.Ribbon/Themes/Office2013/Generic.txt index 93b22e479..7b21250bd 100644 --- a/Fluent/Themes/Office2013/Generic.txt +++ b/Fluent.Ribbon/Themes/Office2013/Generic.txt @@ -1,51 +1,56 @@ -Office2013\Colors\Colors.xaml -Office2013\Colors\ColorsWhite.xaml -Office2013\Images\Images.xaml -Generic\Controls\EmptyFocusStyle.xaml -Office2010\Controls\ApplicationMenuItem.xaml -Office2013\Controls\ApplicationMenu.xaml -Office2013\Controls\Backstage.xaml -Office2013\Controls\RibbonTabItem.xaml -Office2013\Controls\RibbonTabControl.xaml -Office2013\Controls\RibbonGroupBox.xaml -Office2013\Controls\ScreenTip.xaml -Generic\Controls\TwoLineLabel.xaml -Office2013\Controls\Button.xaml -Office2013\Controls\ToggleButton.xaml -Office2013\Controls\DropDownButton.xaml -Office2013\Controls\SplitButton.xaml -Office2013\Controls\CheckBox.xaml -Generic\Controls\RadioButton.xaml -Generic\Controls\GalleryGroupContainer.xaml -Generic\Controls\RibbonScrollViewer.xaml -Office2013\Controls\RibbonContextualTabGroup.xaml -Generic\Controls\RibbonTitleBar.xaml -Office2013\Controls\KeyTip.xaml -Office2013\Controls\QuickAccessToolBar.xaml -Office2013\Controls\Menu.xaml -Office2013\Controls\MenuItem.xaml -Generic\Controls\MenuSeparator.xaml -Generic\Controls\RibbonMenu.xaml -Office2013\Controls\Gallery.xaml -Office2013\Controls\GalleryItem.xaml -Office2013\Controls\ComboBoxItem.xaml -Office2013\Controls\InRibbonGallery.xaml -Office2013\Controls\BackstageTabItem.xaml -Office2013\Controls\BackstageControls.xaml -Office2013\Controls\BackstageTabControl.xaml -Office2013\Controls\RibbonSeparator.xaml -Generic\Controls\RibbonToolBar.xaml -Generic\Controls\RibbonToolBarControlGroup.xaml -Office2013\Controls\StatusBar.xaml -Office2013\Controls\ScrollBar.xaml -Generic\Controls\RibbonTextBox.xaml -Generic\Controls\TextBox.xaml -Office2013\Controls\Spinner.xaml -Office2013\Controls\ComboBox.xaml -Office2013\Controls\Ribbon.xaml -Office2010\Controls\ColorGallery.xaml -Generic\Controls\SeparatorTabItem.xaml -Office2013\Controls\RibbonStatusBar.xaml -Office2013\Controls\Slider.xaml -Office2013\RibbonWindow.xaml +Generic\Controls\Button.xaml +Generic\Controls\WindowCommands.xaml +Office2013\Colors\Colors.xaml +Office2013\Colors\ColorsWhite.xaml +Office2013\Images\Images.xaml +Generic\Controls\EmptyFocusStyle.xaml +Office2010\Controls\ApplicationMenuItem.xaml +Office2013\Controls\ApplicationMenu.xaml +Office2013\Controls\Backstage.xaml +Office2013\Controls\RibbonTabItem.xaml +Office2013\Controls\RibbonTabControl.xaml +Office2013\Controls\RibbonGroupBox.xaml +Office2013\Controls\ScreenTip.xaml +Generic\Controls\TwoLineLabel.xaml +Office2013\Controls\Button.xaml +Office2013\Controls\ToggleButton.xaml +Office2013\Controls\DropDownButton.xaml +Office2013\Controls\SplitButton.xaml +Office2013\Controls\CheckBox.xaml +Generic\Controls\RadioButton.xaml +Generic\Controls\GalleryGroupContainer.xaml +Generic\Controls\RibbonScrollViewer.xaml +Office2013\Controls\RibbonContextualTabGroup.xaml +Generic\Controls\RibbonTitleBar.xaml +Office2013\Controls\KeyTip.xaml +Office2013\Controls\QuickAccessToolBar.xaml +Office2013\Controls\Menu.xaml +Office2013\Controls\MenuItem.xaml +Generic\Controls\MenuSeparator.xaml +Generic\Controls\RibbonMenu.xaml +Office2013\Controls\Gallery.xaml +Office2013\Controls\GalleryItem.xaml +Office2013\Controls\ComboBoxItem.xaml +Office2013\Controls\InRibbonGallery.xaml +Office2013\Controls\BackstageTabItem.xaml +Office2013\Controls\BackstageControls.xaml +Office2013\Controls\BackstageTabControl.xaml +Generic\Controls\StartScreen.xaml +Generic\Controls\StartScreenTabControlTemplate.xaml +Office2013\Controls\StartScreenTabControl.xaml +Office2013\Controls\RibbonSeparator.xaml +Generic\Controls\RibbonToolBar.xaml +Generic\Controls\RibbonToolBarControlGroup.xaml +Office2013\Controls\StatusBar.xaml +Office2013\Controls\ScrollBar.xaml +Generic\Controls\RibbonTextBox.xaml +Generic\Controls\TextBox.xaml +Office2013\Controls\Spinner.xaml +Office2013\Controls\ComboBox.xaml +Office2013\Controls\Ribbon.xaml +Office2010\Controls\ColorGallery.xaml +Generic\Controls\SeparatorTabItem.xaml +Office2013\Controls\RibbonStatusBar.xaml +Office2013\Controls\Slider.xaml +Office2013\RibbonWindow.xaml Generic\Common.xaml \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Images/Checked.png b/Fluent.Ribbon/Themes/Office2013/Images/Checked.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Checked.png rename to Fluent.Ribbon/Themes/Office2013/Images/Checked.png diff --git a/Fluent/Themes/Office2013/Images/Copy.png b/Fluent.Ribbon/Themes/Office2013/Images/Copy.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Copy.png rename to Fluent.Ribbon/Themes/Office2013/Images/Copy.png diff --git a/Fluent/Themes/Office2013/Images/Cut.png b/Fluent.Ribbon/Themes/Office2013/Images/Cut.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Cut.png rename to Fluent.Ribbon/Themes/Office2013/Images/Cut.png diff --git a/Fluent/Themes/Office2013/Images/Help.png b/Fluent.Ribbon/Themes/Office2013/Images/Help.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Help.png rename to Fluent.Ribbon/Themes/Office2013/Images/Help.png diff --git a/Fluent/Themes/Office2013/Images/Images.xaml b/Fluent.Ribbon/Themes/Office2013/Images/Images.xaml similarity index 98% rename from Fluent/Themes/Office2013/Images/Images.xaml rename to Fluent.Ribbon/Themes/Office2013/Images/Images.xaml index 5d929d178..8d18225ba 100644 --- a/Fluent/Themes/Office2013/Images/Images.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Images/Images.xaml @@ -1,29 +1,29 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Office2013/Images/MoreColors.png b/Fluent.Ribbon/Themes/Office2013/Images/MoreColors.png similarity index 100% rename from Fluent/Themes/Office2013/Images/MoreColors.png rename to Fluent.Ribbon/Themes/Office2013/Images/MoreColors.png diff --git a/Fluent/Themes/Office2013/Images/Paste.png b/Fluent.Ribbon/Themes/Office2013/Images/Paste.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Paste.png rename to Fluent.Ribbon/Themes/Office2013/Images/Paste.png diff --git a/Fluent/Themes/Office2013/Images/Warning.png b/Fluent.Ribbon/Themes/Office2013/Images/Warning.png similarity index 100% rename from Fluent/Themes/Office2013/Images/Warning.png rename to Fluent.Ribbon/Themes/Office2013/Images/Warning.png diff --git a/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml b/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml new file mode 100644 index 000000000..82f11ce02 --- /dev/null +++ b/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Windows8/Colors/Colors.xaml b/Fluent.Ribbon/Themes/Windows8/Colors/Colors.xaml similarity index 100% rename from Fluent/Themes/Windows8/Colors/Colors.xaml rename to Fluent.Ribbon/Themes/Windows8/Colors/Colors.xaml diff --git a/Fluent/Themes/Windows8/Colors/ColorsSilver.xaml b/Fluent.Ribbon/Themes/Windows8/Colors/ColorsSilver.xaml similarity index 100% rename from Fluent/Themes/Windows8/Colors/ColorsSilver.xaml rename to Fluent.Ribbon/Themes/Windows8/Colors/ColorsSilver.xaml diff --git a/Fluent/Themes/Windows8/Controls/ApplicationMenu.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/ApplicationMenu.xaml similarity index 73% rename from Fluent/Themes/Windows8/Controls/ApplicationMenu.xaml rename to Fluent.Ribbon/Themes/Windows8/Controls/ApplicationMenu.xaml index c2e7a73ac..d01d30d62 100644 --- a/Fluent/Themes/Windows8/Controls/ApplicationMenu.xaml +++ b/Fluent.Ribbon/Themes/Windows8/Controls/ApplicationMenu.xaml @@ -1,21 +1,17 @@  - - - - - - + @@ -28,17 +29,17 @@ + HorizontalAlignment="Center" + Height="32" + VerticalAlignment="Center" + Content="{Binding LargeIcon, RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static Converters:StaticConverters.ObjectToImageConverter}}" + Width="32" + Margin="9,9,9,0" + SnapsToDevicePixels="True" /> + Margin="7,7,7,5" + VerticalAlignment="Center" + Text="{TemplateBinding Header}" /> @@ -156,17 +157,17 @@ + HorizontalAlignment="Center" + Height="32" + VerticalAlignment="Center" + Content="{Binding LargeIcon, RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static Converters:StaticConverters.ObjectToImageConverter}}" + Width="32" + Margin="9,9,9,0" + SnapsToDevicePixels="True" /> + Margin="7,7,7,5" + VerticalAlignment="Center" + Text="{TemplateBinding Header}" /> @@ -292,18 +293,18 @@ + HorizontalAlignment="Center" + Height="32" + VerticalAlignment="Center" + Content="{Binding LargeIcon, RelativeSource={RelativeSource TemplatedParent}, Converter={x:Static Converters:StaticConverters.ObjectToImageConverter}}" + Width="32" + Margin="7,7,7,0" + SnapsToDevicePixels="True" /> + Margin="5,5,5,3" + VerticalAlignment="Center" + HasGlyph="True" + Text="{TemplateBinding Header}" /> @@ -651,8 +652,7 @@ TargetType="{x:Type Fluent:ComboBox}"> - - + diff --git a/Fluent/Themes/Windows8/Controls/BackstageTabItem.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/BackstageTabItem.xaml similarity index 100% rename from Fluent/Themes/Windows8/Controls/BackstageTabItem.xaml rename to Fluent.Ribbon/Themes/Windows8/Controls/BackstageTabItem.xaml diff --git a/Fluent/Themes/Windows8/Controls/Button.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml similarity index 81% rename from Fluent/Themes/Windows8/Controls/Button.xaml rename to Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml index ced61f751..d6768402a 100644 --- a/Fluent/Themes/Windows8/Controls/Button.xaml +++ b/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml @@ -3,39 +3,38 @@ xmlns:Fluent="clr-namespace:Fluent" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:Converters="clr-namespace:Fluent.Converters" mc:Ignorable="d"> - - - - - - + HorizontalAlignment="{TemplateBinding HorizontalAlignment}" + VerticalAlignment="{TemplateBinding VerticalAlignment}" + Height="Auto"> + + + + + Value="2,0,2,0" /> @@ -81,7 +80,7 @@ Value="False" /> + Value="2,0,2,0" /> @@ -139,7 +138,7 @@ Value="{DynamicResource ButtonHoverBackgroundBrush}" /> + Value="{DynamicResource ButtonHoverBorderBrush}" /> diff --git a/Fluent/Themes/Windows8/Controls/CheckBox.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/CheckBox.xaml similarity index 96% rename from Fluent/Themes/Windows8/Controls/CheckBox.xaml rename to Fluent.Ribbon/Themes/Windows8/Controls/CheckBox.xaml index 86ca0d71a..3e40a2ef3 100644 --- a/Fluent/Themes/Windows8/Controls/CheckBox.xaml +++ b/Fluent.Ribbon/Themes/Windows8/Controls/CheckBox.xaml @@ -82,8 +82,7 @@ Fluent:FrameworkHelper.UseLayoutRounding="False" Opacity="0" Stretch="Fill" - Fill="Black" - /> + Fill="Black" /> + + + + + + + diff --git a/Fluent/Themes/Windows8/Controls/ColorGallery.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/ColorGallery.xaml similarity index 99% rename from Fluent/Themes/Windows8/Controls/ColorGallery.xaml rename to Fluent.Ribbon/Themes/Windows8/Controls/ColorGallery.xaml index c01138728..2ca87eada 100644 --- a/Fluent/Themes/Windows8/Controls/ColorGallery.xaml +++ b/Fluent.Ribbon/Themes/Windows8/Controls/ColorGallery.xaml @@ -1,6 +1,7 @@  + xmlns:Fluent="clr-namespace:Fluent" + xmlns:Converters="clr-namespace:Fluent.Converters"> - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Fluent/Themes/Windows8/Silver.xaml b/Fluent.Ribbon/Themes/Windows8/Silver.xaml similarity index 100% rename from Fluent/Themes/Windows8/Silver.xaml rename to Fluent.Ribbon/Themes/Windows8/Silver.xaml diff --git a/Fluent/Themes/XamlCombine.exe b/Fluent.Ribbon/Themes/XamlCombine.exe similarity index 100% rename from Fluent/Themes/XamlCombine.exe rename to Fluent.Ribbon/Themes/XamlCombine.exe diff --git a/Fluent.Ribbon/packages.config b/Fluent.Ribbon/packages.config new file mode 100644 index 000000000..ebc01a62a --- /dev/null +++ b/Fluent.Ribbon/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Fluent/Controls/ComboBox.cs b/Fluent/Controls/ComboBox.cs deleted file mode 100644 index 10ad189d5..000000000 --- a/Fluent/Controls/ComboBox.cs +++ /dev/null @@ -1,982 +0,0 @@ -#region Copyright and License Information - -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright © Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license - -#endregion - -namespace Fluent -{ - using System; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Threading; - using System.Windows; - using System.Windows.Controls; - using System.Windows.Controls.Primitives; - using System.Windows.Data; - using System.Windows.Input; - using System.Windows.Media; - using System.Windows.Media.Imaging; - using System.Windows.Threading; - using Fluent.Internal; - - /// - /// Represents custom Fluent UI ComboBox - /// - [TemplatePart(Name = "PART_ResizeBothThumb", Type = typeof(Thumb))] - [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))] - public class ComboBox : System.Windows.Controls.ComboBox, IQuickAccessItemProvider, IRibbonControl, IDropDownControl - { - #region Fields - - // Thumb to resize in both directions - private Thumb resizeBothThumb; - // Thumb to resize vertical - private Thumb resizeVerticalThumb; - - private IInputElement focusedElement; - - private Panel menuPanel; - - private Border dropDownBorder; - private Border contentBorder; - - private ContentPresenter contentSite; - - // Freezed image (created during snapping) - private Image snappedImage; - - // Is visual currently snapped - private bool isSnapped; - - private GalleryPanel galleryPanel; - - private ScrollViewer scrollViewer; - - private bool canSizeY; - - #endregion - - #region Properties - - #region Size - - /// - /// Gets or sets Size for the element. - /// - public RibbonControlSize Size - { - get { return (RibbonControlSize)this.GetValue(SizeProperty); } - set { this.SetValue(SizeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Size. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ComboBox)); - - #endregion - - #region SizeDefinition - - /// - /// Gets or sets SizeDefinition for element. - /// - public RibbonControlSizeDefinition SizeDefinition - { - get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); } - set { this.SetValue(SizeDefinitionProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for SizeDefinition. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ComboBox)); - - #endregion - - #region KeyTip - - /// - /// Gets or sets KeyTip for element. - /// - public string KeyTip - { - get { return (string)this.GetValue(KeyTipProperty); } - set { this.SetValue(KeyTipProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Keys. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ComboBox)); - - #endregion - - /// - /// Gets drop down popup - /// - public Popup DropDownPopup { get; private set; } - - /// - /// Gets a value indicating whether context menu is opened - /// - public bool IsContextMenuOpened { get; set; } - - #region Header - - /// - /// Gets or sets element Text - /// - public object Header - { - get { return (string)this.GetValue(HeaderProperty); } - set { this.SetValue(HeaderProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Header. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ComboBox)); - - #endregion - - #region Icon - - /// - /// Gets or sets Icon for the element - /// - public object Icon - { - get { return (ImageSource)this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(null, OnIconChanged)); - - private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var element = d as ComboBox; - var oldElement = e.OldValue as FrameworkElement; - if (oldElement != null) element.RemoveLogicalChild(oldElement); - var newElement = e.NewValue as FrameworkElement; - if (newElement != null) element.AddLogicalChild(newElement); - } - - #endregion - - #region Menu - - /// - /// Gets or sets menu to show in combo box bottom - /// - public RibbonMenu Menu - { - get { return (RibbonMenu)this.GetValue(MenuProperty); } - set { this.SetValue(MenuProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty MenuProperty = - DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(ComboBox), new UIPropertyMetadata(null)); - - #endregion - - #region InputWidth - - /// - /// Gets or sets width of the value input part of combobox - /// - public double InputWidth - { - get { return (double)this.GetValue(InputWidthProperty); } - set { this.SetValue(InputWidthProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty InputWidthProperty = - DependencyProperty.Register("InputWidth", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ItemHeight - - /// - /// Gets or sets items height - /// - public double ItemHeight - { - get { return (double)this.GetValue(ItemHeightProperty); } - set { this.SetValue(ItemHeightProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ItemHeightProperty = - DependencyProperty.Register("ItemHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region GroupBy - - /// - /// Gets or sets name of property which - /// will use to group items in the ComboBox. - /// - public string GroupBy - { - get { return (string)this.GetValue(GroupByProperty); } - set { this.SetValue(GroupByProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupBy. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupByProperty = - DependencyProperty.Register("GroupBy", typeof(string), - typeof(ComboBox), new UIPropertyMetadata(null)); - - #endregion - - #region ResizeMode - - /// - /// Gets or sets context menu resize mode - /// - public ContextMenuResizeMode ResizeMode - { - get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); } - set { this.SetValue(ResizeModeProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty ResizeModeProperty = - DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(ComboBox), new UIPropertyMetadata(ContextMenuResizeMode.None)); - - #endregion - - #region Snapping - - /// - /// Snaps / Unsnaps the Visual - /// (remove visuals and substitute with freezed image) - /// - private bool IsSnapped - { - get { return this.isSnapped; } - set - { - if (value == this.isSnapped) return; - if (this.snappedImage == null) return; - if ((value) && (((int)this.contentSite.ActualWidth > 0) && ((int)this.contentSite.ActualHeight > 0))) - { - // Render the freezed image - RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor); - var renderTargetBitmap = new RenderTargetBitmap((int)this.contentSite.ActualWidth + (int)this.contentSite.Margin.Left + (int)this.contentSite.Margin.Right, - (int)this.contentSite.ActualHeight + (int)this.contentSite.Margin.Top + (int)this.contentSite.Margin.Bottom, 96, 96, - PixelFormats.Pbgra32); - renderTargetBitmap.Render(this.contentSite); - this.snappedImage.Source = renderTargetBitmap; - this.snappedImage.FlowDirection = this.FlowDirection; - /*snappedImage.Width = contentSite.ActualWidth; - snappedImage.Height = contentSite.ActualHeight;*/ - this.snappedImage.Visibility = Visibility.Visible; - this.contentSite.Visibility = Visibility.Hidden; - this.isSnapped = value; - } - else - { - this.snappedImage.Visibility = Visibility.Collapsed; - this.contentSite.Visibility = Visibility.Visible; - this.isSnapped = value; - } - - this.InvalidateVisual(); - } - } - - #endregion - - #region DropDownHeight - - /// - /// Gets or sets initial dropdown height - /// - public double DropDownHeight - { - get { return (double)this.GetValue(DropDownHeightProperty); } - set { this.SetValue(DropDownHeightProperty, value); } - } - - /// - /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding, - /// etc... - /// - public static readonly DependencyProperty DropDownHeightProperty = - DependencyProperty.Register("InitialDropDownHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN)); - - #endregion - - #region ShowPopupOnTop - - /// - /// Gets a value indicating whether popup is shown on top; - /// - public bool ShowPopupOnTop - { - get { return (bool)this.GetValue(ShowPopupOnTopProperty); } - private set { this.SetValue(ShowPopupOnTopPropertyKey, value); } - } - - // - private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(ComboBox), new UIPropertyMetadata(false)); - - /// - /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding, - /// etc... - /// - public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty; - - #endregion - - #endregion - - #region Constructors - - /// - /// Static constructor - /// - [SuppressMessage("Microsoft.Performance", "CA1810")] - static ComboBox() - { - var type = typeof(ComboBox); - ToolTipService.Attach(type); - PopupService.Attach(type); - ContextMenuService.Attach(type); - DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type)); - SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(OnSelectionItemChanged, CoerceSelectedItem)); - } - - private static void OnSelectionItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var combo = d as ComboBox; - if (!combo.isQuickAccessOpened && !combo.isQuickAccessFocused && (combo.quickAccessCombo != null)) combo.UpdateQuickAccessCombo(); - } - - private static object CoerceSelectedItem(DependencyObject d, object basevalue) - { - var combo = d as ComboBox; - if (combo.isQuickAccessOpened || combo.isQuickAccessFocused) return combo.selectedItem; - return basevalue; - } - - /// - /// Default Constructor - /// - public ComboBox() - { - ContextMenuService.Coerce(this); - } - - #endregion - - #region QuickAccess - - /// - /// Gets control which represents shortcut item. - /// This item MUST be syncronized with the original - /// and send command to original one control. - /// - /// Control which represents shortcut item - public virtual FrameworkElement CreateQuickAccessItem() - { - var combo = new ComboBox(); - RibbonControl.BindQuickAccessItem(this, combo); - RibbonControl.Bind(this, combo, "GroupBy", GroupByProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ActualWidth", WidthProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "InputWidth", InputWidthProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ItemHeight", ItemHeightProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "IsEditable", IsEditableProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ResizeMode", ResizeModeProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "Text", TextProperty, BindingMode.TwoWay); - - RibbonControl.Bind(this, combo, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay); - RibbonControl.Bind(this, combo, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay); - combo.DropDownOpened += this.OnQuickAccessOpened; - if (this.IsEditable) combo.GotFocus += this.OnQuickAccessTextBoxGetFocus; - this.quickAccessCombo = combo; - this.UpdateQuickAccessCombo(); - return combo; - } - - private void OnQuickAccessTextBoxGetFocus(object sender, RoutedEventArgs e) - { - this.isQuickAccessFocused = true; - if (!this.isQuickAccessOpened) this.Freeze(); - this.quickAccessCombo.LostFocus += this.OnQuickAccessTextBoxLostFocus; - } - - private void OnQuickAccessTextBoxLostFocus(object sender, RoutedEventArgs e) - { - this.quickAccessCombo.LostFocus -= this.OnQuickAccessTextBoxLostFocus; - if (!this.isQuickAccessOpened) this.Unfreeze(); - this.isQuickAccessFocused = false; - } - - private bool isQuickAccessFocused; - private bool isQuickAccessOpened; - private object selectedItem; - private ComboBox quickAccessCombo; - - private void OnQuickAccessOpened(object sender, EventArgs e) - { - this.isQuickAccessOpened = true; - this.quickAccessCombo.DropDownClosed += this.OnQuickAccessMenuClosed; - this.quickAccessCombo.UpdateLayout(); - if (!this.isQuickAccessFocused) - this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, ((ThreadStart)(() => - { - this.Freeze(); - this.Dispatcher.BeginInvoke(DispatcherPriority.Input, ((ThreadStart)(() => { if (this.quickAccessCombo.SelectedItem != null) (this.quickAccessCombo.ItemContainerGenerator.ContainerFromItem(this.quickAccessCombo.SelectedItem) as ComboBoxItem).BringIntoView(); } - ))); - } - ))); - } - - private void OnQuickAccessMenuClosed(object sender, EventArgs e) - { - this.quickAccessCombo.DropDownClosed -= this.OnQuickAccessMenuClosed; - if (!this.isQuickAccessFocused) this.Unfreeze(); - this.isQuickAccessOpened = false; - } - - private void Freeze() - { - this.IsSnapped = true; - this.selectedItem = this.SelectedItem; - - ItemsControlHelper.MoveItemsToDifferentControl(this, this.quickAccessCombo); - - this.SelectedItem = null; - this.quickAccessCombo.SelectedItem = this.selectedItem; - this.quickAccessCombo.Menu = this.Menu; - this.Menu = null; - this.quickAccessCombo.IsSnapped = false; - } - - private void Unfreeze() - { - var text = this.quickAccessCombo.Text; - this.selectedItem = this.quickAccessCombo.SelectedItem; - this.quickAccessCombo.IsSnapped = true; - - ItemsControlHelper.MoveItemsToDifferentControl(this.quickAccessCombo, this); - - this.quickAccessCombo.SelectedItem = null; - this.SelectedItem = this.selectedItem; - this.Menu = this.quickAccessCombo.Menu; - this.quickAccessCombo.Menu = null; - this.IsSnapped = false; - this.Text = text; - this.UpdateLayout(); - } - - private void UpdateQuickAccessCombo() - { - if (this.IsLoaded == false) - { - this.Loaded += this.OnFirstLoaded; - } - - if (this.IsEditable == false) - { - this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() => - { - this.quickAccessCombo.IsSnapped = true; - this.IsSnapped = true; - if (this.snappedImage != null && - this.quickAccessCombo.snappedImage != null) - { - this.quickAccessCombo.snappedImage.Source = this.snappedImage.Source; - this.quickAccessCombo.snappedImage.Visibility = Visibility.Visible; - if (this.quickAccessCombo.IsSnapped == false) - { - this.quickAccessCombo.isSnapped = true; - } - } - this.IsSnapped = false; - })); - } - } - - private void OnFirstLoaded(object sender, RoutedEventArgs e) - { - this.Loaded -= this.OnFirstLoaded; - this.UpdateQuickAccessCombo(); - } - - /// - /// Gets or sets whether control can be added to quick access toolbar - /// - public bool CanAddToQuickAccessToolBar - { - get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); } - set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, - /// binding, etc... - /// - public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged)); - - #endregion - - #region Overrides - - /// - /// When overridden in a derived class, is invoked whenever application code or internal processes call - /// . - /// - public override void OnApplyTemplate() - { - this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup; - - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta; - } - this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb; - if (this.resizeVerticalThumb != null) - { - this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta; - } - - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta; - } - this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb; - if (this.resizeBothThumb != null) - { - this.resizeBothThumb.DragDelta += this.OnResizeBothDelta; - } - - this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel; - - this.snappedImage = this.GetTemplateChild("PART_SelectedImage") as Image; - this.contentSite = this.GetTemplateChild("PART_ContentSite") as ContentPresenter; - - if (this.contentBorder != null) this.contentBorder.PreviewMouseDown -= this.OnContentBorderPreviewMouseDown; - this.contentBorder = this.GetTemplateChild("PART_ContentBorder") as Border; - if (this.contentBorder != null) this.contentBorder.PreviewMouseDown += this.OnContentBorderPreviewMouseDown; - - this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel; - this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer; - - this.dropDownBorder = this.GetTemplateChild("PART_DropDownBorder") as Border; - - base.OnApplyTemplate(); - } - - /// - /// Reports when a combo box's popup opens. - /// - /// The event data for the event. - protected override void OnDropDownOpened(EventArgs e) - { - base.OnDropDownOpened(e); - - Mouse.Capture(this, CaptureMode.SubTree); - - if (this.SelectedItem != null) - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); - } - - this.focusedElement = Keyboard.FocusedElement; - - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; - } - - this.canSizeY = true; - - this.galleryPanel.Width = double.NaN; - this.scrollViewer.Height = double.NaN; - - var popupChild = this.DropDownPopup.Child as FrameworkElement; - var heightDelta = popupChild.DesiredSize.Height - this.scrollViewer.DesiredSize.Height; - - var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height * 2 / 3, this.MaxDropDownHeight); - - if (double.IsNaN(this.DropDownHeight) == false) - { - initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight); - } - - if (this.scrollViewer.DesiredSize.Height > initialHeight) - { - this.scrollViewer.Height = initialHeight; - } - else - { - initialHeight = this.scrollViewer.DesiredSize.Height; - } - - var monitor = RibbonControl.GetControlMonitor(this); - var delta = monitor.Bottom - this.PointToScreen(new Point()).Y - this.ActualHeight - initialHeight - heightDelta; - - if (delta >= 0) - { - this.ShowPopupOnTop = false; - } - else - { - var deltaTop = this.PointToScreen(new Point()).Y - initialHeight - heightDelta - monitor.Top; - - if (deltaTop > delta) - { - this.ShowPopupOnTop = true; - } - else - { - this.ShowPopupOnTop = false; - } - - if (deltaTop < 0) - { - delta = Math.Max(Math.Abs(delta), Math.Abs(deltaTop)); - - if (delta > this.galleryPanel.GetItemSize().Height) - { - this.scrollViewer.Height = delta; - } - else - { - this.canSizeY = false; - this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height; - } - } - } - - popupChild.UpdateLayout(); - } - - /// - /// Reports when a combo box's popup closes. - /// - /// The event data for the event. - protected override void OnDropDownClosed(EventArgs e) - { - base.OnDropDownClosed(e); - if (Mouse.Captured == this) Mouse.Capture(null); - if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; - this.focusedElement = null; - this.ShowPopupOnTop = false; - this.galleryPanel.Width = double.NaN; - this.scrollViewer.Height = double.NaN; - } - - private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) - { - if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus; - this.focusedElement = Keyboard.FocusedElement; - if (this.focusedElement != null) - { - this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus; - if ((this.IsEditable) && - (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))) - { - this.SelectedItem = this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject); - } - } - } - - /// - /// Invoked when a attached routed event occurs. - /// - /// Event data. - protected override void OnPreviewKeyDown(KeyEventArgs e) - { - if ((this.IsEditable) && ((e.Key == Key.Down) || (e.Key == Key.Up)) && (!this.IsDropDownOpen)) - { - this.IsDropDownOpen = true; - e.Handled = true; - return; - } - - base.OnPreviewKeyDown(e); - } - - /// - /// Invoked when a attached routed event occurs. - /// - /// Event data. - protected override void OnKeyDown(KeyEventArgs e) - { - if (e.Key == Key.Down) - { - Debug.WriteLine("Down pressed. FocusedElement - " + Keyboard.FocusedElement); - if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) - { - var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); - if (indexOfMSelectedItem != this.Menu.Items.Count - 1) - { - Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem + 1) as IInputElement); - } - else - { - if ((this.Items.Count > 0) && (!this.IsEditable)) - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); - } - else Keyboard.Focus(this.Menu.Items[0] as IInputElement); - } - } - else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) - { - var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); - if (indexOfSelectedItem != this.Items.Count - 1) - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem + 1) as IInputElement); - } - else - { - if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); - else - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement); - } - } - } - else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); - e.Handled = true; - Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement); - return; - } - else if (e.Key == Key.Up) - { - Debug.WriteLine("Up pressed. FocusedElement - " + Keyboard.FocusedElement); - if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) - { - var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); - if (indexOfMSelectedItem != 0) - { - Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem - 1) as IInputElement); - } - else - { - if ((this.Items.Count > 0) && (!this.IsEditable)) - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement); - } - else Keyboard.Focus(this.Menu.Items[this.Menu.Items.Count - 1] as IInputElement); - } - } - else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))) - { - var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject); - if (indexOfSelectedItem != 0) - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem - 1) as IInputElement); - } - else - { - if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(this.Menu.Items.Count - 1) as IInputElement); - else - { - Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement); - } - } - } - else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement); - Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement); - e.Handled = true; - return; - } - else if ((e.Key == Key.Return) && (!this.IsEditable) && this.IsDropDownOpen) - { - var element = Keyboard.FocusedElement as DependencyObject; - - // only try to select if we got a focusedElement - if (element != null) - { - var newSelectedIndex = this.ItemContainerGenerator.IndexFromContainer(element); - - // only set the selected index if the focused element was in a container in this combobox - if (newSelectedIndex > -1) - { - this.SelectedIndex = newSelectedIndex; - } - } - } - base.OnKeyDown(e); - } - - #endregion - - #region Methods - - /// - /// Handles key tip pressed - /// - public virtual void OnKeyTipPressed() - { - this.Dispatcher.BeginInvoke( - DispatcherPriority.Normal, - (DispatcherOperationCallback)delegate(object arg) - { - var ctrl = (ComboBox)arg; - - // Edge case: Whole dropdown content is disabled - if (ctrl.IsKeyboardFocusWithin == false) - { - Keyboard.Focus(ctrl); - } - return null; - }, - this); - - if (!this.IsEditable) - { - this.IsDropDownOpen = true; - } - } - - /// - /// Handles back navigation with KeyTips - /// - public void OnKeyTipBack() - { - } - - #endregion - - #region Private methods - - // Prevent reopenning of the dropdown menu (popup) - private void OnContentBorderPreviewMouseDown(object sender, MouseButtonEventArgs e) - { - if (this.IsDropDownOpen) - { - this.IsDropDownOpen = false; - e.Handled = true; - } - } - - // Handles resize both drag - private void OnResizeBothDelta(object sender, DragDeltaEventArgs e) - { - // Set height - this.SetDragHeight(e); - - // Set width - this.menuPanel.Width = double.NaN; - if (double.IsNaN(this.galleryPanel.Width)) - { - this.galleryPanel.Width = this.galleryPanel.ActualWidth; - } - - var monitorRight = RibbonControl.GetControlMonitor(this).Right; - var popupChild = this.DropDownPopup.Child as FrameworkElement; - var delta = monitorRight - this.PointToScreen(new Point()).X - popupChild.ActualWidth - e.HorizontalChange; - var deltaX = popupChild.ActualWidth - this.galleryPanel.ActualWidth; - var deltaBorders = this.dropDownBorder.ActualWidth - this.galleryPanel.ActualWidth; - - if (delta > 0) - { - this.galleryPanel.Width = Math.Max(0, Math.Max(this.galleryPanel.Width + e.HorizontalChange, this.ActualWidth - deltaBorders)); - } - else - { - this.galleryPanel.Width = Math.Max(0, Math.Max(monitorRight - this.PointToScreen(new Point()).X - deltaX, this.ActualWidth - deltaBorders)); - } - } - - // Handles resize vertical drag - private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e) - { - this.SetDragHeight(e); - } - - private void SetDragHeight(DragDeltaEventArgs e) - { - if (!this.canSizeY) - { - return; - } - - if (double.IsNaN(this.scrollViewer.Height)) - { - this.scrollViewer.Height = this.scrollViewer.ActualHeight; - } - - if (this.ShowPopupOnTop) - { - var monitorTop = RibbonControl.GetControlMonitor(this).Top; - - // Calc shadow height - var delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - e.VerticalChange - monitorTop; - if (delta > 0) - { - this.scrollViewer.Height = Math.Max(0, - Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); - } - else - { - delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - monitorTop; - this.scrollViewer.Height = Math.Max(0, - Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight)); - } - } - else - { - var monitorBottom = RibbonControl.GetControlMonitor(this).Bottom; - var popupChild = this.DropDownPopup.Child as FrameworkElement; - var delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight - e.VerticalChange; - if (delta > 0) - { - this.scrollViewer.Height = Math.Max(0, - Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight)); - } - else - { - delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight; - this.scrollViewer.Height = Math.Max(0, - Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight)); - } - } - } - - #endregion - } -} \ No newline at end of file diff --git a/Fluent/Controls/GalleryGroupIcon.cs b/Fluent/Controls/GalleryGroupIcon.cs deleted file mode 100644 index 7b2d2844e..000000000 --- a/Fluent/Controls/GalleryGroupIcon.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Degtyarev Daniel, Rikker Serg. 2009-2010. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Windows; -using System.Windows.Media; - -namespace Fluent -{ - /// - /// Represents gallery group icon definition - /// - public class GalleryGroupIcon : DependencyObject - { - /// - /// Gets or sets group name - /// - public string GroupName - { - get { return (string)this.GetValue(GroupNameProperty); } - set { this.SetValue(GroupNameProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for GroupName. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty GroupNameProperty = - DependencyProperty.Register("GroupName", typeof(string), - typeof(GalleryGroupIcon), new UIPropertyMetadata(null)); - - - /// - /// Gets or sets group icon - /// - public ImageSource Icon - { - get { return (ImageSource)this.GetValue(IconProperty); } - set { this.SetValue(IconProperty, value); } - } - - /// - /// Using a DependencyProperty as the backing store for Icon. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty IconProperty = - DependencyProperty.Register("Icon", typeof(ImageSource), typeof(GalleryGroupIcon), - new UIPropertyMetadata(null)); - } -} diff --git a/Fluent/Fluent dotNET 4.0.csproj.DotSettings b/Fluent/Fluent dotNET 4.0.csproj.DotSettings deleted file mode 100644 index 662f95686..000000000 --- a/Fluent/Fluent dotNET 4.0.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - CSharp50 \ No newline at end of file diff --git a/Fluent/Fluent dotNET 4.5.csproj.DotSettings b/Fluent/Fluent dotNET 4.5.csproj.DotSettings deleted file mode 100644 index 662f95686..000000000 --- a/Fluent/Fluent dotNET 4.5.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - CSharp50 \ No newline at end of file diff --git a/Fluent/Internal/UIHelper.cs b/Fluent/Internal/UIHelper.cs deleted file mode 100644 index f6a0fb2e7..000000000 --- a/Fluent/Internal/UIHelper.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Fluent.Internal -{ - using System; - using System.Windows; - using System.Windows.Media; - - /// - /// Class with helper functions for UI related stuff - /// - internal class UIHelper - { - /// - /// Tries to find immediate visual child of type which matches - /// - /// - /// The visual child of type that matches . - /// Returns null if no child matches. - /// - public static T FindImmediateVisualChild(DependencyObject parent, Predicate predicate) - where T : DependencyObject - { - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) - { - var obj = VisualTreeHelper.GetChild(parent, i) as T; - - if (obj != null - && predicate(obj)) - { - return obj; - } - } - - return null; - } - - /// - /// Gets the first visual child of type TChildItem by walking down the visual tree. - /// - /// The type of visual child to find. - /// The parent element whose visual tree shall be walked down. - /// The first element of type TChildItem found in the visual tree is returned. If none is found, null is returned. - public static TChildItem FindVisualChild(DependencyObject obj) where TChildItem : DependencyObject - { - for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) - { - var child = VisualTreeHelper.GetChild(obj, i); - var item = child as TChildItem; - - if (item != null) - return item; - - var childOfChild = FindVisualChild(child); - if (childOfChild != null) - return childOfChild; - } - return null; - } - - } -} \ No newline at end of file diff --git a/Fluent/Internal/WindowSizing.cs b/Fluent/Internal/WindowSizing.cs deleted file mode 100644 index 757246fa2..000000000 --- a/Fluent/Internal/WindowSizing.cs +++ /dev/null @@ -1,287 +0,0 @@ -namespace Fluent.Internal -{ - using System; - using System.Diagnostics; - using System.Runtime.InteropServices; - using System.Windows; - using System.Windows.Interop; - using Fluent.Metro.Native; - - /// - /// Encapsulates logic for window sizing (maximizing etc.) - /// - public class WindowSizing - { - private readonly RibbonWindow window; - private IntPtr windowHwnd; - private bool fixingWindowChromeBug; - - /// - /// Creates a new instance and binds it to - /// - public WindowSizing(RibbonWindow window) - { - this.window = window; - - this.window.StateChanged += this.HandleWindowStateChanged; - } - - /// - /// Called when has been initialize - /// - public void WindowInitialized() - { - var hwndSource = PresentationSource.FromVisual(this.window) as HwndSource; - if (hwndSource != null) - { - this.windowHwnd = hwndSource.Handle; - hwndSource.AddHook(this.HwndHook); - - this.window.Dispatcher.BeginInvoke((Action)(this.FixWindowChromeBug)); - } - } - - private void HandleWindowStateChanged(object sender, EventArgs e) - { - this.window.Dispatcher.BeginInvoke((Action)(this.FixWindowChromeBug)); - } - - private void FixWindowChromeBug() - { - if (this.fixingWindowChromeBug) - { - return; - } - - this.fixingWindowChromeBug = true; - - if (this.window.WindowState == WindowState.Maximized) - { - this.FixWindowChromeBugForMaximizedWindow(); - } - else if (this.window.SizeToContent == SizeToContent.WidthAndHeight) - { - // SizeToContent is reset to manual as soon as the window is resized anyway. - // By changing it to manual early on we avoid black areas by refreshing the window. - this.window.SizeToContent = SizeToContent.Manual; - } - - this.fixingWindowChromeBug = false; - } - - private IntPtr HwndHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) - { - var returnval = IntPtr.Zero; - - switch (message) - { - case Constants.WM_SIZE: - // When window is maximized and was not responding, windows issues another WM_SIZE when window is responding again so we need to shift the window position back and forth - // Fixes #80, #159 and #170 - if (this.GetWindowPlacement().showCmd == 3) - { - this.FixWindowChromeBugForMaximizedWindow(); - } - break; - - case Constants.WM_GETMINMAXINFO: - this.FixMinMaxInfo(hWnd, lParam, out handled); - break; - } - - return returnval; - } - - private WINDOWPLACEMENT GetWindowPlacement() - { - WINDOWPLACEMENT windowPlacement; - UnsafeNativeMethods.GetWindowPlacement(this.windowHwnd, out windowPlacement); - return windowPlacement; - } - - #region Fixes - - private void FixMinMaxInfo(IntPtr hWnd, IntPtr lParam, out bool handled) - { - if (this.GetWindowPlacement().showCmd == 3) - { - /* http://blogs.msdn.com/b/llobo/archive/2006/08/01/maximizing-window-_2800_with-windowstyle_3d00_none_2900_-considering-taskbar.aspx */ - this.WmGetMinMaxInfo(hWnd, lParam); - - handled = true; - return; - } - - handled = false; - } - - private void FixWindowChromeBugForMaximizedWindow() - { - var mmi = this.GetMinMaxInfo(this.windowHwnd, new MINMAXINFO()); - if (NativeMethods.IsDwmEnabled()) - { - UnsafeNativeMethods.MoveWindow(this.windowHwnd, mmi.ptMaxPosition.X + 10, mmi.ptMaxPosition.Y, mmi.ptMaxSize.X, mmi.ptMaxSize.Y, true); - UnsafeNativeMethods.MoveWindow(this.windowHwnd, mmi.ptMaxPosition.X, mmi.ptMaxPosition.Y, mmi.ptMaxSize.X, mmi.ptMaxSize.Y, true); - } - else - { - UnsafeNativeMethods.MoveWindow(this.windowHwnd, mmi.ptMaxPosition.X, mmi.ptMaxPosition.Y + 1, mmi.ptMaxSize.X, mmi.ptMaxSize.Y, true); - UnsafeNativeMethods.MoveWindow(this.windowHwnd, mmi.ptMaxPosition.X, mmi.ptMaxPosition.Y, mmi.ptMaxSize.X, mmi.ptMaxSize.Y, true); - } - } - - #endregion - - #region WindowSize - - private bool IgnoreTaskBar() - { - //var ignoreTaskBar = this.AssociatedObject.IgnoreTaskbarOnMaximize - // || this.AssociatedObject.WindowStyle == WindowStyle.None; - - return false; - } - - private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam) - { - var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); - - mmi = this.GetMinMaxInfo(hwnd, mmi); - - Marshal.StructureToPtr(mmi, lParam, true); - } - - private MINMAXINFO GetMinMaxInfo(IntPtr hwnd, MINMAXINFO mmi) - { - // Adjust the maximized size and position to fit the work area of the correct monitor - var monitor = UnsafeNativeMethods.MonitorFromWindow(hwnd, Constants.MONITOR_DEFAULTTONEAREST); - - if (monitor == IntPtr.Zero) - { - return mmi; - } - - var monitorInfo = new MONITORINFO(); - UnsafeNativeMethods.GetMonitorInfo(monitor, monitorInfo); - var rcWorkArea = monitorInfo.rcWork; - var rcMonitorArea = monitorInfo.rcMonitor; - - Debug.WriteLine("Monitor-Info"); - Debug.WriteLine(string.Format("Work: {0}", rcWorkArea)); - Debug.WriteLine(string.Format("Mon : {0}", rcMonitorArea)); - - Debug.WriteLine(string.Format("Before: {0}", mmi)); - - mmi.ptMaxPosition.X = rcWorkArea.left; - mmi.ptMaxPosition.Y = rcWorkArea.top; - - var ignoreTaskBar = this.IgnoreTaskBar(); - - var x = ignoreTaskBar ? monitorInfo.rcMonitor.left : monitorInfo.rcWork.left; - var y = ignoreTaskBar ? monitorInfo.rcMonitor.top : monitorInfo.rcWork.top; - var maxWidth = ignoreTaskBar ? Math.Abs(monitorInfo.rcMonitor.right - x) : Math.Abs(monitorInfo.rcWork.right - x); - var maxHeight = ignoreTaskBar ? Math.Abs(monitorInfo.rcMonitor.bottom - y) : Math.Abs(monitorInfo.rcWork.bottom - y); - - var maxWindowWidth = double.IsPositiveInfinity(this.window.MaxWidth) ? maxWidth : (int)this.window.MaxWidth; - var maxWindowHeight = double.IsPositiveInfinity(this.window.MaxHeight) ? maxHeight : (int)this.window.MaxHeight; - - mmi.ptMaxSize.X = Math.Min(maxWidth, maxWindowWidth); - mmi.ptMaxSize.Y = Math.Min(maxHeight, maxWindowHeight); - - if (!ignoreTaskBar) - { - mmi.ptMaxTrackSize.X = mmi.ptMaxSize.X; - mmi.ptMaxTrackSize.Y = mmi.ptMaxSize.Y; - mmi = AdjustWorkingAreaForAutoHide(monitor, mmi); - } - - Debug.WriteLine(string.Format("After: {0}", mmi)); - - return mmi; - } - - private static int GetEdge(RECT rc) - { - int uEdge; - - if (rc.top == rc.left - && rc.bottom > rc.right) - { - uEdge = (int)ABEdge.ABE_LEFT; - } - else if (rc.top == rc.left - && rc.bottom < rc.right) - { - uEdge = (int)ABEdge.ABE_TOP; - } - else if (rc.top > rc.left) - { - uEdge = (int)ABEdge.ABE_BOTTOM; - } - else - { - uEdge = (int)ABEdge.ABE_RIGHT; - } - - return uEdge; - } - - /// - /// This method handles the window size if the taskbar is set to auto-hide. - /// - private static MINMAXINFO AdjustWorkingAreaForAutoHide(IntPtr monitorContainingApplication, MINMAXINFO mmi) - { - var hwnd = UnsafeNativeMethods.FindWindow("Shell_TrayWnd", null); - var monitorWithTaskbarOnIt = UnsafeNativeMethods.MonitorFromWindow(hwnd, Constants.MONITOR_DEFAULTTONEAREST); - - if (monitorContainingApplication.Equals(monitorWithTaskbarOnIt) == false) - { - return mmi; - } - - var abd = new APPBARDATA(); - abd.cbSize = Marshal.SizeOf(abd); - abd.hWnd = hwnd; - UnsafeNativeMethods.SHAppBarMessage((int)ABMsg.ABM_GETTASKBARPOS, ref abd); - var uEdge = GetEdge(abd.rc); - var autoHide = UnsafeNativeMethods.SHAppBarMessage((int)ABMsg.ABM_GETSTATE, ref abd) == new IntPtr(1); - - if (!autoHide) - { - return mmi; - } - - switch (uEdge) - { - case (int)ABEdge.ABE_LEFT: - mmi.ptMaxPosition.X += 2; - mmi.ptMaxTrackSize.X -= 2; - mmi.ptMaxSize.X -= 2; - break; - - case (int)ABEdge.ABE_RIGHT: - mmi.ptMaxSize.X -= 2; - mmi.ptMaxTrackSize.X -= 2; - break; - - case (int)ABEdge.ABE_TOP: - mmi.ptMaxPosition.Y += 2; - mmi.ptMaxTrackSize.Y -= 2; - mmi.ptMaxSize.Y -= 2; - break; - - case (int)ABEdge.ABE_BOTTOM: - mmi.ptMaxSize.Y -= 2; - mmi.ptMaxTrackSize.Y -= 2; - break; - - default: - return mmi; - } - - return mmi; - } - - #endregion WindowSize - } -} \ No newline at end of file diff --git a/Fluent/Metro/Behaviours/BorderlessWindowBehaviour.cs b/Fluent/Metro/Behaviours/BorderlessWindowBehaviour.cs deleted file mode 100644 index f4f952b0d..000000000 --- a/Fluent/Metro/Behaviours/BorderlessWindowBehaviour.cs +++ /dev/null @@ -1,148 +0,0 @@ -namespace Fluent.Metro.Behaviours -{ - using System; - using System.Windows; - using System.Windows.Interactivity; - using System.Windows.Interop; - using Fluent.Metro.Native; - - /// - /// Behavior for borderless windows (used for Office 2013 theme) - /// - public class BorderlessWindowBehavior : Behavior - { - private HwndSource hwndSource; - - /// - /// Called when behavior is being attached - /// - protected override void OnAttached() - { - if (PresentationSource.FromVisual(this.AssociatedObject) != null) - { - this.AddHwndHook(); - } - else - { - this.AssociatedObject.SourceInitialized += this.HandleAssociatedObject_SourceInitialized; - } - - base.OnAttached(); - } - - /// - /// Called when behavior is being detached - /// - protected override void OnDetaching() - { - this.AssociatedObject.SourceInitialized -= this.HandleAssociatedObject_SourceInitialized; - - this.RemoveHwndHook(); - base.OnDetaching(); - } - - private void AddHwndHook() - { - this.hwndSource = PresentationSource.FromVisual(this.AssociatedObject) as HwndSource; - if (this.hwndSource != null) - { - this.hwndSource.AddHook(this.HwndHook); - } - } - - private void RemoveHwndHook() - { - this.AssociatedObject.SourceInitialized -= this.HandleAssociatedObject_SourceInitialized; - if (this.hwndSource != null) - { - this.hwndSource.RemoveHook(this.HwndHook); - } - - this.hwndSource = null; - } - - private void HandleAssociatedObject_SourceInitialized(object sender, EventArgs e) - { - this.AddHwndHook(); - } - - private IntPtr HwndHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) - { - var returnval = IntPtr.Zero; - - switch (message) - { - case Constants.WM_NCHITTEST: - // don't process the message on windows that are maximized as those don't have a resize border at all - if (this.AssociatedObject.WindowState == WindowState.Maximized) - { - break; - } - - // don't process the message on windows that can't be resized - var resizeMode = this.AssociatedObject.ResizeMode; - if (resizeMode == ResizeMode.CanMinimize - || resizeMode == ResizeMode.NoResize) - { - break; - } - - // get X & Y out of the message - var screenPoint = new Point(UnsafeNativeMethods.GET_X_LPARAM(lParam), UnsafeNativeMethods.GET_Y_LPARAM(lParam)); - - // convert to window coordinates - var windowPoint = this.AssociatedObject.PointFromScreen(screenPoint); - var windowSize = this.AssociatedObject.RenderSize; - var windowRect = new Rect(windowSize); - windowRect.Inflate(-6, -6); - - // don't process the message if the mouse is outside the 6px resize border - if (windowRect.Contains(windowPoint)) - { - break; - } - - var windowHeight = (int)windowSize.Height; - var windowWidth = (int)windowSize.Width; - - // create the rectangles where resize arrows are shown - var topLeft = new Rect(0, 0, 6, 6); - var top = new Rect(6, 0, windowWidth - 12, 6); - var topRight = new Rect(windowWidth - 6, 0, 6, 6); - - var left = new Rect(0, 6, 6, windowHeight - 12); - var right = new Rect(windowWidth - 6, 6, 6, windowHeight - 12); - - var bottomLeft = new Rect(0, windowHeight - 6, 6, 6); - var bottom = new Rect(6, windowHeight - 6, windowWidth - 12, 6); - var bottomRight = new Rect(windowWidth - 6, windowHeight - 6, 6, 6); - - // check if the mouse is within one of the rectangles - if (topLeft.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTTOPLEFT; - else if (top.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTTOP; - else if (topRight.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTTOPRIGHT; - else if (left.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTLEFT; - else if (right.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTRIGHT; - else if (bottomLeft.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTBOTTOMLEFT; - else if (bottom.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTBOTTOM; - else if (bottomRight.Contains(windowPoint)) - returnval = (IntPtr)Constants.HTBOTTOMRIGHT; - - if (returnval != IntPtr.Zero) - { - handled = true; - } - - break; - } - return returnval; - } - } -} \ No newline at end of file diff --git a/Fluent/Metro/Behaviours/WindowSettingBehavior.cs b/Fluent/Metro/Behaviours/WindowSettingBehavior.cs deleted file mode 100644 index 71b3ef339..000000000 --- a/Fluent/Metro/Behaviours/WindowSettingBehavior.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Fluent.Metro.Behaviours -{ - using System.Windows.Interactivity; - using Fluent.Metro.Controls; - - /// - /// Encapsulates the use of - /// - public class WindowsSettingBehavior : Behavior - { - /// - /// Called when behavior is being attached - /// - protected override void OnAttached() - { - WindowSettings.SetSave(this.AssociatedObject, this.AssociatedObject.SaveWindowPosition); - } - } -} \ No newline at end of file diff --git a/Fluent/Metro/Controls/MetroWindow.cs b/Fluent/Metro/Controls/MetroWindow.cs deleted file mode 100644 index d181368e9..000000000 --- a/Fluent/Metro/Controls/MetroWindow.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using Fluent.Metro.Native; - -namespace Fluent -{ - //public class MetroWindow : Window - //{ - // static MetroWindow() - // { - // DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroWindow), new FrameworkPropertyMetadata(typeof(MetroWindow))); - // StyleProperty.OverrideMetadata(typeof(MetroWindow), new FrameworkPropertyMetadata(null, OnCoerceStyle)); - // } - - // private static object OnCoerceStyle(DependencyObject d, object basevalue) - // { - // if (basevalue != null) - // { - // return basevalue; - // } - - // var frameworkElement = d as FrameworkElement; - // if (frameworkElement != null) - // { - // basevalue = frameworkElement.TryFindResource(typeof(MetroWindow)); - // } - - // return basevalue; - // } - //} -} \ No newline at end of file diff --git a/Fluent/Metro/Controls/WindowSettings.cs b/Fluent/Metro/Controls/WindowSettings.cs deleted file mode 100644 index b8c7cee1f..000000000 --- a/Fluent/Metro/Controls/WindowSettings.cs +++ /dev/null @@ -1,152 +0,0 @@ -using System; -using System.ComponentModel; -using System.Configuration; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Interop; -using Fluent.Metro.Native; - -namespace Fluent.Metro.Controls -{ - /// - /// Stores settings for a - /// - public class WindowSettings - { - /// - /// Using a DependencyProperty as the backing store for Save. - /// This enables animation, styling, binding, etc... - /// - public static readonly DependencyProperty SaveProperty = DependencyProperty.RegisterAttached("Save", typeof(bool), typeof(WindowSettings), new FrameworkPropertyMetadata(OnSaveInvalidated)); - - /// - /// Sets Save for dependencyObject - /// - public static void SetSave(DependencyObject dependencyObject, bool enabled) - { - dependencyObject.SetValue(SaveProperty, enabled); - } - - internal class WindowApplicationSettings : ApplicationSettingsBase - { - public WindowApplicationSettings(WindowSettings windowSettings) - : base(windowSettings._window.GetType().FullName) - { - } - - [UserScopedSetting] - public WINDOWPLACEMENT? Placement - { - get - { - if (this["Placement"] != null) - { - return ((WINDOWPLACEMENT)this["Placement"]); - } - - return null; - } - set - { - this["Placement"] = value; - } - } - } - - private Window _window; - - /// - /// Creates a new instance which uses - /// - public WindowSettings(Window window) - { - this._window = window; - } - - private static void OnSaveInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - var window = dependencyObject as Window; - if (window == null || !((bool)e.NewValue)) - { - return; - } - - var settings = new WindowSettings(window); - settings.Attach(); - } - - /// - /// Loads the - /// - protected virtual void LoadWindowState() - { - this.Settings.Reload(); - - if (this.Settings.Placement == null) - { - return; - } - - try - { - var wp = this.Settings.Placement.Value; - - wp.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); - wp.flags = 0; - wp.showCmd = (wp.showCmd == Constants.SW_SHOWMINIMIZED ? Constants.SW_SHOWNORMAL : wp.showCmd); - var hwnd = new WindowInteropHelper(this._window).Handle; - UnsafeNativeMethods.SetWindowPlacement(hwnd, ref wp); - } - catch (Exception ex) - { - Trace.WriteLine(string.Format("Failed to load window state:\r\n{0}", ex)); - } - } - - /// - /// Saves the - /// - protected virtual void SaveWindowState() - { - WINDOWPLACEMENT wp; - var hwnd = new WindowInteropHelper(this._window).Handle; - UnsafeNativeMethods.GetWindowPlacement(hwnd, out wp); - this.Settings.Placement = wp; - this.Settings.Save(); - } - - private void Attach() - { - if (this._window == null) return; - this._window.Closing += this.WindowClosing; - this._window.SourceInitialized += this.WindowSourceInitialized; - } - - private void WindowSourceInitialized(object sender, EventArgs e) - { - this.LoadWindowState(); - } - - private void WindowClosing(object sender, CancelEventArgs e) - { - this.SaveWindowState(); - this._window.Closing -= this.WindowClosing; - this._window.SourceInitialized -= this.WindowSourceInitialized; - this._window = null; - } - - private WindowApplicationSettings _windowApplicationSettings; - - internal virtual WindowApplicationSettings CreateWindowApplicationSettingsInstance() - { - return new WindowApplicationSettings(this); - } - - [Browsable(false)] - internal WindowApplicationSettings Settings - { - get { return this._windowApplicationSettings ?? (this._windowApplicationSettings = this.CreateWindowApplicationSettingsInstance()); } - } - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/ABEdge.cs b/Fluent/Metro/Native/ABEdge.cs deleted file mode 100644 index fbf6b1cf6..000000000 --- a/Fluent/Metro/Native/ABEdge.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Fluent.Metro.Native -{ - internal enum ABEdge - { - ABE_LEFT = 0, - ABE_TOP = 1, - ABE_RIGHT = 2, - ABE_BOTTOM = 3 - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/ABMsg.cs b/Fluent/Metro/Native/ABMsg.cs deleted file mode 100644 index ade42f1fa..000000000 --- a/Fluent/Metro/Native/ABMsg.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Fluent.Metro.Native -{ - internal enum ABMsg - { - ABM_NEW = 0, - ABM_REMOVE = 1, - ABM_QUERYPOS = 2, - ABM_SETPOS = 3, - ABM_GETSTATE = 4, - ABM_GETTASKBARPOS = 5, - ABM_ACTIVATE = 6, - ABM_GETAUTOHIDEBAR = 7, - ABM_SETAUTOHIDEBAR = 8, - ABM_WINDOWPOSCHANGED = 9, - ABM_SETSTATE = 10 - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/APPBARDATA.cs b/Fluent/Metro/Native/APPBARDATA.cs deleted file mode 100644 index da0bfe4f7..000000000 --- a/Fluent/Metro/Native/APPBARDATA.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Fluent.Metro.Native -{ - using System; - using System.Runtime.InteropServices; - - [StructLayout(LayoutKind.Sequential)] - internal struct APPBARDATA - { - public int cbSize; - public IntPtr hWnd; - public int uCallbackMessage; - public int uEdge; - public RECT rc; - public bool lParam; - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/CREATESTRUCT.cs b/Fluent/Metro/Native/CREATESTRUCT.cs deleted file mode 100644 index 61d6f71fd..000000000 --- a/Fluent/Metro/Native/CREATESTRUCT.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] - internal struct CREATESTRUCT - { - public IntPtr lpCreateParams; - public IntPtr hInstance; - public IntPtr hMenu; - public IntPtr hwndParent; - public int cy; - public int cx; - public int y; - public int x; - public int style; - public string lpszName; - public string lpszClass; - public int dwExStyle; - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/MARGINS.cs b/Fluent/Metro/Native/MARGINS.cs deleted file mode 100644 index a673712bf..000000000 --- a/Fluent/Metro/Native/MARGINS.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [StructLayout(LayoutKind.Sequential)] - internal struct MARGINS - { - public int leftWidth; - public int rightWidth; - public int topHeight; - public int bottomHeight; - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/MINMAXINFO.cs b/Fluent/Metro/Native/MINMAXINFO.cs deleted file mode 100644 index 48a525769..000000000 --- a/Fluent/Metro/Native/MINMAXINFO.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [StructLayout(LayoutKind.Sequential)] - internal struct MINMAXINFO - { - public POINT ptReserved; - public POINT ptMaxSize; - public POINT ptMaxPosition; - public POINT ptMinTrackSize; - public POINT ptMaxTrackSize; - - public override string ToString() - { - return string.Format("MINMAXINFO {{ ptMaxPosition : {0} / ptMaxSize : {1} }}", this.ptMaxPosition, this.ptMaxSize); - } - }; -} \ No newline at end of file diff --git a/Fluent/Metro/Native/POINT.cs b/Fluent/Metro/Native/POINT.cs deleted file mode 100644 index 1af834c1d..000000000 --- a/Fluent/Metro/Native/POINT.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [Serializable] - [StructLayout(LayoutKind.Sequential)] - internal struct POINT - { - private int x; - private int y; - - public POINT(int x, int y) - { - this.x = x; - this.y = y; - } - - public int X - { - get { return this.x; } - set { this.x = value; } - } - - public int Y - { - get { return this.y; } - set { this.y = value; } - } - - public override bool Equals(object obj) - { - if (obj is POINT) - { - var point = (POINT)obj; - - return point.x == this.x && point.y == this.y; - } - - return base.Equals(obj); - } - public override int GetHashCode() - { - return this.x.GetHashCode() ^ this.y.GetHashCode(); - } - - public static bool operator ==(POINT a, POINT b) - { - return a.x == b.x && a.y == b.y; - } - - public static bool operator !=(POINT a, POINT b) - { - return !(a == b); - } - - public override string ToString() - { - return string.Format("POINT {{ x: {0} / y: {1} }}", this.X, this.Y); - } - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/UnsafeNativeMethods.cs b/Fluent/Metro/Native/UnsafeNativeMethods.cs deleted file mode 100644 index a45e73157..000000000 --- a/Fluent/Metro/Native/UnsafeNativeMethods.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -namespace Fluent.Metro.Native -{ - using System.Diagnostics.CodeAnalysis; - using System.Runtime.Versioning; - using System.Windows; - - /// http://msdn.microsoft.com/en-us/library/ms182161.aspx - [SuppressUnmanagedCodeSecurity] - internal static class UnsafeNativeMethods - { - [DllImport("user32.dll", SetLastError = true)] - internal static extern bool MoveWindow(IntPtr hwnd, int x, int y, int width, int height, bool repaint); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969518%28v=vs.85%29.aspx - [DllImport("dwmapi", PreserveSig = false, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DwmIsCompositionEnabled(); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969512%28v=vs.85%29.aspx - [DllImport("dwmapi", PreserveSig = true, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)] - [return: MarshalAs(UnmanagedType.Error)] - internal static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, [In] ref MARGINS pMarInset); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969524%28v=vs.85%29.aspx - [DllImport("dwmapi", PreserveSig = true, CallingConvention = CallingConvention.Winapi, ExactSpelling = true)] - internal static extern int DwmSetWindowAttribute([In] IntPtr hwnd, [In] int attr, [In] ref int attrValue, [In] int attrSize); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633572%28v=vs.85%29.aspx - [DllImport("user32", CallingConvention = CallingConvention.Winapi)] - internal static extern IntPtr DefWindowProc([In] IntPtr hwnd, [In] int msg, [In] IntPtr wParam, [In] IntPtr lParam); - - /// http://msdn.microsoft.com/en-us/library/dd144901%28v=VS.85%29.aspx - [DllImport("user32", EntryPoint = "GetMonitorInfoW", ExactSpelling = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetMonitorInfo([In] IntPtr hMonitor, [Out] MONITORINFO lpmi); - - /// http://msdn.microsoft.com/en-us/library/dd145064%28v=VS.85%29.aspx - [DllImport("user32")] - internal static extern IntPtr MonitorFromWindow([In] IntPtr handle, [In] int flags); - - [DllImport("user32.dll", SetLastError = true)] - internal static extern IntPtr MonitorFromPoint(POINT pt, MONITORINFO.MonitorOptions dwFlags); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633545(v=vs.85).aspx - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms647486%28v=vs.85%29.aspx - [DllImport("user32", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadStringW", SetLastError = true, CallingConvention = CallingConvention.Winapi)] - internal static extern int LoadString([In] [Optional] IntPtr hInstance, [In] uint uID, [Out] StringBuilder lpBuffer, [In] int nBufferMax); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633528(v=vs.85).aspx - [DllImport("user32", CharSet = CharSet.Auto, ExactSpelling = true)] - internal static extern bool IsWindow([In] [Optional] IntPtr hWnd); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms647985(v=vs.85).aspx - [DllImport("user32")] - internal static extern IntPtr GetSystemMenu([In] IntPtr hWnd, [In] bool bRevert); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648003(v=vs.85).aspx - [DllImport("user32")] - internal static extern uint TrackPopupMenuEx([In] IntPtr hmenu, [In] uint fuFlags, [In] int x, [In] int y, [In] IntPtr hwnd, [In] [Optional] IntPtr lptpm); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx - [DllImport("user32", EntryPoint = "PostMessage", SetLastError = true)] - private static extern bool _PostMessage([In] [Optional] IntPtr hWnd, [In] uint Msg, [In] IntPtr wParam, [In] IntPtr lParam); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648390(v=vs.85).aspx - [DllImport("user32")] - internal static extern bool GetCursorPos([Out] out POINT pt); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646258(v=vs.85).aspx - [DllImport("user32", CharSet = CharSet.Auto, ExactSpelling = true)] - internal static extern int GetDoubleClickTime(); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx - [DllImport("kernel32", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryW", SetLastError = true, CallingConvention = CallingConvention.Winapi)] - internal static extern IntPtr LoadLibrary([In] [MarshalAs(UnmanagedType.LPWStr)] string lpFileName); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683152%28v=vs.85%29.aspx - [DllImport("kernel32", CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool FreeLibrary([In] IntPtr hModule); - - //SetClassLong won't work correctly for 64-bit: we should use SetClassLongPtr instead. On - //32-bit, SetClassLongPtr is just #defined as SetClassLong. SetClassLong really should - //take/return int instead of IntPtr/HandleRef, but since we're running this only for 32-bit - //it'll be OK. - public static IntPtr SetClassLong(HandleRef hWnd, int nIndex, IntPtr dwNewLong) - { - if (IntPtr.Size == 4) - { - return SetClassLongPtr32(hWnd, nIndex, dwNewLong); - } - return SetClassLongPtr64(hWnd, nIndex, dwNewLong); - } - - [SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable")] - [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetClassLong")] - [ResourceExposure(ResourceScope.None)] - private static extern IntPtr SetClassLongPtr32(HandleRef hwnd, int nIndex, IntPtr dwNewLong); - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetClassLongPtr")] - [ResourceExposure(ResourceScope.None)] - private static extern IntPtr SetClassLongPtr64(HandleRef hwnd, int nIndex, IntPtr dwNewLong); - - internal static IntPtr GetClassLong(IntPtr hWnd, int nIndex) - { - if (IntPtr.Size == 4) - { - return new IntPtr(GetClassLong32(hWnd, nIndex)); - } - - return GetClassLong64(hWnd, nIndex); - } - - [DllImport("user32.dll", EntryPoint = "GetClassLong")] - private static extern uint GetClassLong32(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - private static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex); - - [DllImport("gdi32.dll")] - internal static extern IntPtr CreateSolidBrush(int crColor); - - [DllImport("gdi32.dll")] - internal static extern bool DeleteObject(IntPtr hObject); - - [DllImport("user32.dll")] - internal static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl); - - [DllImport("user32.dll")] - internal static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl); - - /// http://msdn.microsoft.com/en-us/library/windows/desktop/ms647636(v=vs.85).aspx - [DllImport("user32.dll")] - internal static extern uint EnableMenuItem(IntPtr hMenu, uint itemId, uint uEnable); - - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); - - [DllImportAttribute("user32.dll")] - public static extern bool ReleaseCapture(); - - internal static void PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam) - { - if (!_PostMessage(hWnd, Msg, wParam, lParam)) - { - throw new Win32Exception(); - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Win32Point - { - public readonly int X; - public readonly int Y; - }; - - // See: http://stackoverflow.com/questions/7913325/win-api-in-c-get-hi-and-low-word-from-intptr/7913393#7913393 - internal static Point GetPoint(IntPtr ptr) - { - uint xy = unchecked(IntPtr.Size == 8 ? (uint)ptr.ToInt64() : (uint)ptr.ToInt32()); - int x = unchecked((short)xy); - int y = unchecked((short)(xy >> 16)); - return new Point(x, y); - } - - internal static int GET_X_LPARAM(IntPtr lParam) - { - return LOWORD(lParam.ToInt32()); - } - - internal static int GET_Y_LPARAM(IntPtr lParam) - { - return HIWORD(lParam.ToInt32()); - } - - private static int HIWORD(long i) - { - return (short)(i >> 16); - } - - private static int LOWORD(long i) - { - return (short)(i & 0xFFFF); - } - - internal const int GWL_STYLE = -16; - internal const int WS_SYSMENU = 0x80000; - [DllImport("user32.dll", SetLastError = true)] - internal static extern int GetWindowLong(IntPtr hWnd, int nIndex); - [DllImport("user32.dll")] - internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("shell32.dll", CallingConvention = CallingConvention.StdCall)] - public static extern IntPtr SHAppBarMessage(int dwMessage, ref APPBARDATA pData); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); - } -} \ No newline at end of file diff --git a/Fluent/Metro/Native/WINDOWPLACEMENT.cs b/Fluent/Metro/Native/WINDOWPLACEMENT.cs deleted file mode 100644 index 53b232e39..000000000 --- a/Fluent/Metro/Native/WINDOWPLACEMENT.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Fluent.Metro.Native -{ -#pragma warning disable 1591 - [Serializable] - [StructLayout(LayoutKind.Sequential)] - internal struct WINDOWPLACEMENT - { - public int length; - - public int flags; - - public int showCmd; - - public POINT minPosition; - - public POINT maxPosition; - - public RECT normalPosition; - - public override string ToString() - { - return string.Format( - "WINDOWPLACEMENT\n{{\nlength: {0}\nflags: {1}\nshowCmd: {2}\nminPosition: {3}\nmaxPosition: {4}\nnormalPosition: {5}\n}}" - , this.length, this.flags, this.showCmd, this.minPosition, this.maxPosition, this.normalPosition); - } - } -} \ No newline at end of file diff --git a/Fluent/Properties/AssemblyInfo.cs b/Fluent/Properties/AssemblyInfo.cs deleted file mode 100644 index 0ec88352f..000000000 --- a/Fluent/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright Degtyarev Daniel, Rikker Serg. 2009-2013. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -using System.Reflection; -using System.Runtime.InteropServices; -using System.Windows.Markup; - -[assembly: AssemblyTitle("Fluent")] -[assembly: AssemblyDescription("Fluent Ribbon Control Suite")] - -[assembly: Guid("d849f751-e8f4-480d-acc0-6148eafcaafc")] - -[assembly: XmlnsPrefix("urn:fluent-ribbon", "fluent")] -[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent")] -[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent.Converters")] -[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent.Metro.Behaviours")] -[assembly: XmlnsDefinition("urn:fluent-ribbon", "Fluent.Metro.Controls")] \ No newline at end of file diff --git a/Fluent/Themes/Office2010/RibbonWindow.xaml b/Fluent/Themes/Office2010/RibbonWindow.xaml deleted file mode 100644 index ef6f12b56..000000000 --- a/Fluent/Themes/Office2010/RibbonWindow.xaml +++ /dev/null @@ -1,715 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FluentTest/App.xaml.cs b/FluentTest/App.xaml.cs deleted file mode 100644 index a99087e1a..000000000 --- a/FluentTest/App.xaml.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace FluentTest -{ - public partial class App - { - public App() - { - //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru-RU"); - - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("fa"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("ru"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("de"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("hu"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("cs"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("pl"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("nl"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("pt-PT"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("pt-br"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("es"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("sv"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("sk"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("uk"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("ro"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("it"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("ar"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("da"); - //Thread.CurrentThread.CurrentUICulture = new CultureInfo("az"); - } - } -} \ No newline at end of file diff --git a/FluentTest/Commanding/IRelayCommand.cs b/FluentTest/Commanding/IRelayCommand.cs deleted file mode 100644 index 74a799d61..000000000 --- a/FluentTest/Commanding/IRelayCommand.cs +++ /dev/null @@ -1,20 +0,0 @@ -#region Copyright and License Information -// Fluent Ribbon Control Suite -// http://fluent.codeplex.com/ -// Copyright (c) Bastian "batzen" Schmidt 2014. All rights reserved. -// -// Distributed under the terms of the Microsoft Public License (Ms-PL). -// The license is available online http://fluent.codeplex.com/license -#endregion - -namespace FluentTest.Commanding -{ - using System; - using System.Windows.Input; - - public interface IRelayCommand : ICommand - { - event EventHandler Executed; - event EventHandler Executing; - } -} \ No newline at end of file diff --git a/FluentTest/FluentTest dotNET 4.0.csproj.DotSettings b/FluentTest/FluentTest dotNET 4.0.csproj.DotSettings deleted file mode 100644 index 662f95686..000000000 --- a/FluentTest/FluentTest dotNET 4.0.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - CSharp50 \ No newline at end of file diff --git a/FluentTest/FluentTest dotNET 4.5.csproj.DotSettings b/FluentTest/FluentTest dotNET 4.5.csproj.DotSettings deleted file mode 100644 index 662f95686..000000000 --- a/FluentTest/FluentTest dotNET 4.5.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - CSharp50 \ No newline at end of file diff --git a/FluentTest/Properties/AssemblyInfo.cs b/FluentTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 660e9d73d..000000000 --- a/FluentTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("Fluent Showcase")] -[assembly: AssemblyDescription("Showcase of Fluent Ribbon Control Suite")] \ No newline at end of file diff --git a/FluentTest/ViewModels/FontsViewModel.cs b/FluentTest/ViewModels/FontsViewModel.cs deleted file mode 100644 index acf416920..000000000 --- a/FluentTest/ViewModels/FontsViewModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace FluentTest.ViewModels -{ - public class FontsViewModel : ViewModel - { - private readonly string[] data = { "Tahoma", "Segoe UI", "Arial", "Courier New", "Symbol" }; - - public string[] FontsData - { - get { return this.data; } - } - } -} diff --git a/FluentTest/ViewModels/GalleryItemViewModel.cs b/FluentTest/ViewModels/GalleryItemViewModel.cs deleted file mode 100644 index 4a9a41acc..000000000 --- a/FluentTest/ViewModels/GalleryItemViewModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace FluentTest.ViewModels -{ - public class GalleryItemViewModel - { - public GalleryItemViewModel(string group, string text) - { - this.Group = group; - this.Text = text; - } - - public string Text { get; set; } - - public string Group { get; set; } - } -} \ No newline at end of file diff --git a/FluentTest/app.manifest b/FluentTest/app.manifest deleted file mode 100644 index 9d4194ed3..000000000 --- a/FluentTest/app.manifest +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/FluentTest/packages.config b/FluentTest/packages.config deleted file mode 100644 index 84802b1a1..000000000 --- a/FluentTest/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Lib/Net40/Microsoft.Windows.Shell.dll b/Lib/Net40/Microsoft.Windows.Shell.dll deleted file mode 100644 index 497b64e37..000000000 Binary files a/Lib/Net40/Microsoft.Windows.Shell.dll and /dev/null differ diff --git a/Lib/Net40/Microsoft.Windows.Shell.pdb b/Lib/Net40/Microsoft.Windows.Shell.pdb deleted file mode 100644 index 53086882a..000000000 Binary files a/Lib/Net40/Microsoft.Windows.Shell.pdb and /dev/null differ diff --git a/Lib/Net40/Microsoft.Windows.Shell.xml b/Lib/Net40/Microsoft.Windows.Shell.xml deleted file mode 100644 index 0c34e971f..000000000 --- a/Lib/Net40/Microsoft.Windows.Shell.xml +++ /dev/null @@ -1,647 +0,0 @@ - - - - Microsoft.Windows.Shell - - - - Represents the base class for the and classes. - - - Gets or sets the name of the category the is grouped with in the Windows 7 taskbar Jump List. - The name of the category the is grouped with. The default is null. - - - Describes why a could not be added to the Jump List by the Windows shell. - - - The reason is not specified. - - - The references an invalid file path, or the operating system does not support Jump Lists. - - - The application is not registered to handle the file name extension of the . - - - The item was previously in the Jump List but was removed by the user. - - - Provides data for the event. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class that has the specified parameters. - The list of Jump List items that could not be added to the Jump List by the Windows shell. - The list of reasons why the rejected Jump List items could not be added to the Jump List. - The count of does not equal the count of rejection . - - - Gets the list of Jump List items that could not be added to the Jump List by the Windows shell. - The list of Jump List items that could not be added to the Jump List by the Windows shell. - - - Gets the list of reasons why the rejected Jump List items could not be added to the Jump List. - The list of reasons why the rejected Jump List items could not be added to the Jump List. - - - Provides data for the event. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class that has the specified parameters. - The list of Jump List items that were removed by the user since was last called. - - - Gets the list of Jump List items that have been removed by the user since the method was last called. - The list of Jump List items that have been removed by the user since the method was last called. - - - Represents a list of items and tasks displayed as a menu on a Windows 7 taskbar button. - - - Initializes a new instance of the class. - - - Initializes a new instance of the class with the specified parameters. - The collection of objects that are displayed in the Jump List. - A value that indicates whether frequently used items are displayed in the Jump List. - A value that indicates whether recently used items are displayed in the Jump List. - - - Adds the specified jump path to the Recent category of the Jump List. - The to add to the Jump List. - - - Adds the specified jump task to the Recent category of the Jump List. - The to add to the Jump List. - - - Adds the specified item path to the Recent category of the Jump List. - The path to add to the Jump List. - - - Sends the to the Windows shell in its current state. - The is not completely initialized. - - - Signals the start of the initialization. - This call to is nested in a previous call to . - - - Signals the end of the initialization. - This call to is not paired with a call to . - - - Returns the object associated with an application. - The object associated with the specified application. - The application associated with the . - - - Gets the collection of objects that are displayed in the Jump List. - The collection of objects displayed in the Jump List. The default is an empty collection. - - - Occurs when jump items are not successfully added to the Jump List by the Windows shell. - - - Occurs when jump items previously in the Jump List are removed from the list by the user. - - - Sets the object associated with an application. - The application associated with the . - The to associate with the application. - - - Gets or sets a value that indicates whether frequently used items are displayed in the Jump List. - true if frequently used items are displayed in the Jump List; otherwise, false. The default is false. - - - Gets or sets a value that indicates whether recently used items are displayed in the Jump List. - true if recently used items are displayed in the Jump List; otherwise, false. The default is false. - - - Represents a link to a file that is displayed in a Windows 7 taskbar Jump List. - - - Initializes a new instance of the class. - - - Gets or sets the path to the file to be included in the Jump List. - The path to the file to be included in the Jump List. - - - Represents a shortcut to an application in the Windows 7 taskbar Jump List. - - - Initializes a new instance of the class. - - - Gets or sets the path to the application. - The path to the application. The default is null. - - - Gets or sets the arguments passed to the application on startup. - The arguments passed to the application on startup. The default is null. - - - Gets or sets the text displayed in the tooltip for the task in the Jump List. - The text displayed in the tooltip for the task. The default is null. - - - Gets or sets the zero-based index of an icon embedded in a resource. - The zero-based index of the icon, or -1 if no icon is used. The default is 0. - - - Gets or sets the path to a resource that contains the icon to display in the Jump List. - The path to a resource that contains the icon. The default is null. - - - Gets or sets the text displayed for the task in the Jump List. - The text displayed for the task in the Jump List. The default is null. - - - Gets or sets the working directory of the application on startup. - The working directory of the application on startup. The default is null. - - - Specifies constants that indicate which edges of the window frame are not owned by the client. - - - All edges are owned by the client (value = 0). - - - The left edge is not owned by the client (value = 1). - - - The top edge is not owned by the client (value = 2). - - - The right edge is not owned by the client (value = 4). - - - The bottom edge is not owned by the client (value = 8). - - - Specifies constants that indicate the direction of the resize grip behavior on an input element. - - - No resize behavior is specified. - - - The window resizes from its top-left corner. - - - The window resizes from its top edge. - - - The window resizes from its top-right corner. - - - The window resizes from its right edge. - - - The window resizes from its bottom-right corner. - - - The window resizes from its bottom edge. - - - The window resizes from its bottom-left corner. - - - The windows resizes from its left edge. - - - Defines routed commands that are common to window management. - - - Closes the specified window. - The window to close. - - - Gets a command that closes a window. - A command that closes a window. - - - Maximizes the specified window. - The window to maximize. - - - Gets a command that maximizes a window. - A command that maximizes a window. - - - Minimizes the specified window. - The window to minimize. - - - Gets a command that maximizes a window. - A command that maximizes a window. - - - Restores the specified widow. - The window to restore. - - - Gets a command that restores a window. - A command that restores a window. - - - Displays the system menu for the specified window. - The window to have its system menu displayed. - The location of the system menu. - - - Gets a command that displays the system menu. - A command that displays the system menu. - - - Contains properties that you can use to query system settings of the non-client area of a window. - - - Gets an instance of the class. - An instance of the class. - - - Gets a value that indicates whether the high contrast feature is being used. - true if the high contrast feature is being used; otherwise, false. - - - Gets a value that indicates whether glass window frames are being used. - true if glass window frames are being used; otherwise, false. - - - Occurs when one of the properties changes. - - - Gets the recommended size, in pixels, of a small icon. - The recommended size, in pixels, of a small icon. - - - Gets the color theme name. - The color theme name. - - - Gets the theme name. - The theme name. - - - Gets a that indicates the default location of the minimize, maximize, and close buttons. - An object that indicates the default location of the minimize, maximize, and close buttons. - - - Gets the height of the area that contains the minimize, maximize, and close buttons. - The height of the area that contains the minimize, maximize, and close buttons. - - - Gets the degree to which the corners of a window are rounded. - The degree to which the corners of a window are rounded. - - - Gets the brush that paints the glass window frame. - The brush that paints the glass window frame. - - - Gets the color that is used to paint the glass window frame. - The color that is used to paint the glass window frame. - - - Gets the size of the non-client area of the window. - The size of the non-client area of the window, in device-independent pixels (1/96th of an inch). - - - Gets the size of the resizing border around the window. - The size of the resizing border around the window, in device-independent pixels (1/96th of an inch). - - - Represents information about how the taskbar thumbnail is displayed. - - - Initializes a new instance of the class. - - - Gets or sets the text for the taskbar item tooltip. - The text for the taskbar item tooltip. The default is an empty string. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets the value of the attached property for an object. - The object’s property value. - The object from which the property value is read. - - - Gets or sets the image that is displayed over the program icon in the taskbar button. - The image that is displayed over the program icon in the taskbar button. The default is null. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates how the progress indicator is displayed in the taskbar button. - An enumeration value that indicates how the progress indicator is displayed in the taskbar button. The default is . - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates the fullness of the progress indicator in the taskbar button. - A value that indicates the fullness of the progress indicator in the taskbar button. The default is 0. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Sets the value of the attached property for an object. - The object to which the attached property is written. - The value to set. - - - Gets or sets a that is attached to a window. - The that is attached to the window. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets the collection of objects that are associated with the . - The collection of objects that are associated with the . The default is an empty collection. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that specifies the part of the application window's client area that is displayed in the taskbar thumbnail. - A value that specifies the part of the application window's client area that is displayed in the taskbar thumbnail. The default is an empty . - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Specifies the state of the progress indicator in the Windows taskbar. - - - No progress indicator is displayed in the taskbar button. - - - A pulsing green indicator is displayed in the taskbar button. - - - A green progress indicator is displayed in the taskbar button. - - - A red progress indicator is displayed in the taskbar button. - - - A yellow progress indicator is displayed in the taskbar button. - - - Represents information about how to display a button in the Windows 7 taskbar thumbnail. - - - Initializes a new instance of the class. - - - Occurs when the thumbnail button is clicked. - - - Gets or sets the command to invoke when this thumbnail button is clicked. - The command to invoke when this thumbnail button is clicked. The default is null. - - - Gets or sets the parameter to pass to the property. - The parameter to pass to the property. The default is null. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets the element on which to raise the specified command. - The element on which to raise the specified command. The default is null. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets the text to display for the thumbnail button tooltip. - The text to display for the thumbnail button tooltip. The default is an empty string. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates whether the taskbar thumbnail closes when the thumbnail button is clicked. - true if the thumbnail closes; otherwise, false. The default is false. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets the image that is displayed on the thumbnail button. - The image that is displayed on the thumbnail button. The default is null. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates whether a border and highlight is displayed around the thumbnail button. - true if a border and highlight is displayed around the thumbnail button; otherwise, false. The default is true. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates whether the thumbnail button is enabled. - true if the thumbnail button is enabled; otherwise, false. The default is true. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that indicates whether the user can interact with the thumbnail button. - true if the user can interact with the thumbnail button; otherwise, false. The default is true. - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Gets or sets a value that specifies the display state of the thumbnail button. - An enumeration value that specifies the display state of the thumbnail button. The default is . - - - Identifies the  dependency property. - The identifier for the  dependency property. - - - Represents a collection of objects that are associated with a . - - - Initializes a new instance of the class. - - - Creates a new instance of the collection. - The new instance of the collection. - - - Represents an object that describes the customizations to the non-client area of a window. - - - Initializes a new instance of the class. - - - Gets or sets the height of the caption area at the top of a window. - The height of the caption area. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets a value that indicates the amount that the corners of a window are rounded. - A value that describes the amount that corners are rounded. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Creates a new instance of the class. - The new instance of this class. - - - Gets the value of the attached property from the specified input element. - The value of the attached property. - The input element from which to read the property value. - - is null. - - is not a . - - - Gets the value of the attached property from the specified input element. - The value of the attached property. - The input element from which to read the property value. - - is null. - - is not a . - - - Gets the value of the attached property from the specified . - The instance of that is attached to the specified . - The from which to read the property value. - - is null. - - - Gets a uniform thickness of -1. - A uniform thickness of -1 in all cases. - - - Gets or sets a value that indicates the width of the glass border around a window. - The width of the glass border around a window. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets a value that indicates whether WPF hit-testing is enabled on the part of an element that is in the non-client area of a window. - true if hit testing is enabled in the non-client area; otherwise, false. The registered default is false. For more information about what can influence the value, see Dependency Property Value Precedence. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets a value that indicates which edges of the window frame are not owned by the client. - A bitwise combination of the enumeration values that specify which edges of the frame are not owned by the client.The registered default is . For more information about what can influence the value, see Dependency Property Value Precedence. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets a value that indicates the width of the border that is used to resize a window. - The width of the border that is used to resize a window. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets a value that indicates the direction of the resize grip behavior on an input element. - One of the enumeration values that indicates the direction of the resize grip. The registered default is . For more information about what can influence the value, see Dependency Property Value Precedence. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Sets the value of the attached property on the specified input element. - The element on which to set the attached property. - The property value to set. - - is null. - - is not a . - - - Sets the value of the attached property on the specified input element. - The element on which to set the attached property. - The property value to set. - - is null. - - is not a . - - - Sets the value of the attached property on the specified . - The on which to set the attached property. - The instance of to set. - - is null. - - - Gets or sets a value that indicates whether the Windows Aero caption buttons are shown. - The registered default is true. For more information about what can influence the value, see Dependency Property Value Precedence. - - - Identifies the dependency property. - The identifier for the dependency property. - - - Gets or sets the instance of that is attached to a window. - The instance of attached to window. The registered default is null. For more information about what can influence the value, see Dependency Property Value Precedence. - - - Identifies the dependency property. - The identifier for the dependency property. - - - \ No newline at end of file diff --git a/Lib/Net40/System.Windows.Interactivity.dll b/Lib/Net40/System.Windows.Interactivity.dll deleted file mode 100644 index bd0bc6ccb..000000000 Binary files a/Lib/Net40/System.Windows.Interactivity.dll and /dev/null differ diff --git a/Lib/Net45/System.Windows.Interactivity.dll b/Lib/Net45/System.Windows.Interactivity.dll deleted file mode 100644 index 931c744c8..000000000 Binary files a/Lib/Net45/System.Windows.Interactivity.dll and /dev/null differ diff --git a/License.txt b/License.txt index 7c4cae238..0f188b9ef 100644 --- a/License.txt +++ b/License.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2009-2014 Degtyarev Daniel, Rikker Serg, Bastian Schmidt (https://github.com/fluentribbon/Fluent.Ribbon) +Copyright (c) 2009-2015 Bastian Schmidt, Degtyarev Daniel, Rikker Serg (https://github.com/fluentribbon/Fluent.Ribbon) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MSBuildHelper.ps1 b/MSBuildHelper.ps1 new file mode 100644 index 000000000..9606ed81d --- /dev/null +++ b/MSBuildHelper.ps1 @@ -0,0 +1,166 @@ +Add-Type -TypeDefinition @" + public enum MSBuildPath + { + MSBuildToolsPath, + MSBuildToolsRoot + } +"@ + +Add-Type -TypeDefinition @" + public enum Platform + { + Current, + x86, + x64 + } +"@ + +function Using-Object +{ + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [AllowEmptyString()] + [AllowEmptyCollection()] + [AllowNull()] + [Object] + $InputObject, + + [Parameter(Mandatory = $true)] + [scriptblock] + $ScriptBlock + ) + + try + { + . $ScriptBlock + } + finally + { + if ($null -ne $InputObject -and $InputObject -is [System.IDisposable]) + { + $InputObject.Dispose() + } + } +} + +function Get-MSBuildVersion() +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$False)] + $Version = $null, + [Parameter(Mandatory=$False)] + [switch]$All = $false + ) + + $versions = dir HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\ | %{ new-object System.Version ((Split-Path $_.Name -Leaf)) } | Sort-Object -Descending + + if ($All) + { + return $versions + } + + if ($null -eq $Version) + { + return $versions[0] + } + + foreach ($currentVersion in $versions) + { + if ($currentVersion -eq $Version) + { + return $currentVersion + } + } + + foreach ($currentVersion in $versions) + { + if ($currentVersion.Major -eq $Version) + { + return $currentVersion + } + } + + Write-Error "MSBuild version $Version could not be found" + + return $null +} + +function Get-MSBuildPath() +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$True)] + [MSBuildPath]$Path, + [Parameter(Mandatory=$False)] + $Version = $null, + [Parameter(Mandatory=$False)] + [Platform]$Platform = [Platform]::Current + ) + + $foundVersion = Get-MSBuildVersion $Version -ErrorAction SilentlyContinue + + if ($null -eq $foundVersion) + { + Write-Error "MSBuild version $Version could not be found" + return + } + + switch ($Platform) + { + Current { $registryView = [Microsoft.Win32.RegistryView]::Default } + x86 { $registryView = [Microsoft.Win32.RegistryView]::Registry32 } + x64 { $registryView = [Microsoft.Win32.RegistryView]::Registry64 } + } + + Using-Object ($key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $registryView)) { + Using-Object ($subKey = $key.OpenSubKey("SOFTWARE\Microsoft\MSBuild\ToolsVersions\$foundVersion")) { + $resolvedPath = $subKey.GetValue($Path) + + if ($resolvedPath -eq $null) + { + Write-Error "Could not resolve path for version '$foundVersion' and '$Path'" + return $null + } + + Write-Verbose "$Path : $resolvedPath" + + return $resolvedPath + } + } +} + +function Get-MSBuild() +{ + [CmdletBinding()] + Param( + [Parameter(Mandatory=$False)] + $Version = $null, + [Parameter(Mandatory=$False)] + [Platform]$Platform = [Platform]::Current + ) + + $toolsPath = Get-MSBuildPath MSBuildToolsPath -Version $Version -Platform $Platform + + if ($null -eq $toolsPath) + { + Write-Error "MSBuild could not be found" + return + } + + return Join-Path $toolsPath "msbuild.exe" +} + +#Get-MSBuildVersion -All +#Get-MSBuildPath MSBuildToolsPath -Verbose +#Get-MSBuildPath MSBuildToolsRoot -Verbose + +#Get-MSBuildPath MSBuildToolsPath -Platform x86 -Verbose +#Get-MSBuildPath MSBuildToolsPath -Platform x64 -Verbose +#Get-MSBuild 1 -ErrorAction Continue +#Get-MSBuild 2 +#Get-MSBuild 3 +#Get-MSBuild 3.5 +#Get-MSBuild 12 +#Get-MSBuild 14 -Platform x86 -Verbose \ No newline at end of file diff --git a/README.md b/README.md index 852a766a3..8195cfac0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Fluent.Ribbon or "Fluent Ribbon Control Suite" +Fluent.Ribbon ============= [![Join the chat at https://gitter.im/fluentribbon/Fluent.Ribbon](https://img.shields.io/badge/GITTER-join%20chat-green.svg?style=flat-square)](https://gitter.im/fluentribbon/Fluent.Ribbon?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -13,7 +13,7 @@ Fluent.Ribbon or "Fluent Ribbon Control Suite" This project was previously hosted on [CodePlex](https://fluent.codeplex.com/). -Fluent Ribbon Control Suite is a library that implements an Office-like user interface for the Windows Presentation Foundation (WPF). It provides well-customized controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. It is bundled with the most up-to-date Office 2010, Office 2013 and Windows 8 styles. +Fluent.Ribbon is a library that implements an Office-like user interface for the Windows Presentation Foundation (WPF). It provides controls such as RibbonTabControl, Backstage, Gallery, QuickAccessToolbar, ScreenTip and so on. It is bundled with Office 2010, Office 2013 and Windows 8 themes. ![Fluent.png](https://raw.githubusercontent.com/fluentribbon/Fluent.Ribbon/master/Images/Fluent.png) @@ -21,16 +21,20 @@ Fluent Ribbon Control Suite is a library that implements an Office-like user int ### Contact -If you wish to contact me (batzen) directly please use twitter https://twitter.com/batzendev. +If you wish to contact me (batzen) directly please use [twitter](https://twitter.com/batzendev) or [gitter](https://gitter.im/batzen). ### Contributing #### What you can do to help us -* We are accepting pull requests, so you are very welcome to create one. +* We are accepting pull requests, so you are very welcome to create one * [Fix some bugs](https://github.com/fluentribbon/Fluent.Ribbon/issues) * Help us translating * Help us updating the documentation and walkthrough -* Help us writing a changelog/release notes for the next version + +### Development requirements +* Visual Studio 2015 +* Optional but recommended + * Editorconfig extension for Visual Studio 2015 ### Settings that should be used * Visual Studio settings which should be used @@ -46,11 +50,11 @@ Please, [download walkthrough](https://github.com/fluentribbon/Fluent.Ribbon/blo This document covers the main features of this framework and highlights how to use it, but is pretty outdated right now. Almost all features are shown in the showcase application. If you think there is something missing in the showcase application feel free to create an issue for that. -To be more familiar with Ribbon concept see [msdn article](http://msdn.microsoft.com/en-us/library/cc872782.aspx). +To be more familiar with the Ribbon concept see [msdn article](http://msdn.microsoft.com/en-us/library/cc872782.aspx). -## History & Roadmap +## History & roadmap A history of changes is maintained in the [Changelog](Changelog.md) and the [ReleaseNotes](ReleaseNotes.md). -The (rough) roadmap is done by [milestones](../../milestones). +The roadmap is done by [milestones](../../milestones). ## Feature List | Office UI Element | Status | diff --git a/Shared/GlobalAssemblyInfo.cs b/Shared/GlobalAssemblyInfo.cs index 7f7fd2643..fd4901ab0 100644 --- a/Shared/GlobalAssemblyInfo.cs +++ b/Shared/GlobalAssemblyInfo.cs @@ -10,13 +10,13 @@ [assembly: AssemblyConfiguration("Release")] #endif [assembly: AssemblyCompany("https://github.com/fluentribbon/Fluent.Ribbon")] -[assembly: AssemblyProduct("Fluent Ribbon Control Suite")] -[assembly: AssemblyCopyright("Copyright 2009 - 2015 Degtyarev Daniel, Rikker Serg, Bastian Schmidt")] +[assembly: AssemblyProduct("Fluent.Ribbon")] +[assembly: AssemblyCopyright("Copyright 2012 - 2016 Bastian Schmidt; Copyright 2009 - 2012 Degtyarev Daniel, Rikker Serg")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("3.6.1.0")] -[assembly: AssemblyFileVersion("3.6.1.0")] +[assembly: AssemblyVersion("4.0.0.0")] +[assembly: AssemblyFileVersion("4.0.0.0")] [assembly: AssemblyInformationalVersion("SRC")] [assembly: ComVisible(false)] diff --git a/Tools/nuget.exe b/Tools/nuget.exe index 9ca66594f..9f8781de0 100644 Binary files a/Tools/nuget.exe and b/Tools/nuget.exe differ diff --git a/appveyor.yml b/appveyor.yml index 25ad2f225..70bfa5a90 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,35 +1,84 @@ # http://www.appveyor.com/docs/appveyor-yml -version: 3.6.1.{build} -configuration: Release - -# Install scripts. (runs after repo cloning) -install: - - nuget restore - -build: - verbosity: minimal - -after_build: - - cmd: Tools\GitLink.exe . -u https://github.com/fluentribbon/Fluent.Ribbon - - cmd: nuget pack Fluent.Ribbon.nuspec -Version %appveyor_build_version% -Properties Configuration=%configuration% - - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - -assembly_info: - patch: true - file: Shared\GlobalAssemblyInfo.* - assembly_version: "{version}" - assembly_file_version: "{version}" - assembly_informational_version: "{version}" - -artifacts: - - path: build/bin - name: Fluent.Ribbon.$(appveyor_build_version) - type: zip - -notifications: - - provider: Webhook - url: https://webhooks.gitter.im/e/855da764a995f5aa1a24 - on_build_success: true - on_build_failure: true - on_build_status_changed: false \ No newline at end of file +# configuration for develop/CI branch +- + branches: + only: + - develop + + version: 4.0.0-dev{build} + configuration: Release + + init: + - ps: Update-AppveyorBuild -Version "$($env:appveyor_build_version.Remove($env:appveyor_build_version.IndexOf("-dev") + "-dev".Length))$($env:appveyor_build_number.PadLeft(4, '0'))" + + # Install scripts. (runs after repo cloning) + install: + - nuget restore + + build: + verbosity: minimal + + after_build: + - cmd: Tools\GitLink.exe . -u https://github.com/fluentribbon/Fluent.Ribbon + - cmd: nuget pack Fluent.Ribbon.nuspec -Version %appveyor_build_version% -Properties Configuration=%configuration% + - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + + assembly_info: + patch: true + file: Shared\GlobalAssemblyInfo.* + assembly_version: "{version}" + assembly_file_version: "{version}" + assembly_informational_version: "{version}" + + artifacts: + - path: build/bin + name: Fluent.Ribbon.$(appveyor_build_version) + type: zip + + notifications: + - provider: Webhook + url: https://webhooks.gitter.im/e/855da764a995f5aa1a24 + on_build_success: true + on_build_failure: true + on_build_status_changed: false + +# configuration for master/CI branch +- + branches: + only: + - master + + version: 4.0.0.{build} + configuration: Release + + # Install scripts. (runs after repo cloning) + install: + - nuget restore + + build: + verbosity: minimal + + after_build: + - cmd: Tools\GitLink.exe . -u https://github.com/fluentribbon/Fluent.Ribbon + - cmd: nuget pack Fluent.Ribbon.nuspec -Version %appveyor_build_version% -Properties Configuration=%configuration% + - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + + assembly_info: + patch: true + file: Shared\GlobalAssemblyInfo.* + assembly_version: "{version}" + assembly_file_version: "{version}" + assembly_informational_version: "{version}" + + artifacts: + - path: build/bin + name: Fluent.Ribbon.$(appveyor_build_version) + type: zip + + notifications: + - provider: Webhook + url: https://webhooks.gitter.im/e/855da764a995f5aa1a24 + on_build_success: true + on_build_failure: true + on_build_status_changed: false \ No newline at end of file