优化项目代码格式

This commit is contained in:
polarboy 2024-09-10 10:55:00 +08:00
parent 80638627ee
commit 171734f757
1167 changed files with 11432 additions and 6509 deletions

View File

@ -1,27 +1,19 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_ASSIGNMENTS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_VARIABLES/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_TUPLE_COMPONENTS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_REGION/@EntryValue">2</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_TYPE/@EntryValue">2</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_SINGLE_LINE_COMMENT/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_ASSIGNMENTS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_BINARY_EXPRESSIONS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_COMMENTS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_NESTED_TERNARY/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_PROPERTY_PATTERNS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_SWITCH_EXPRESSIONS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_SWITCH_SECTIONS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_VARIABLES/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OUTDENT_COMMAS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=8715f408_002D64e6_002D4969_002Daba2_002D79f56ef672fa/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Avalonia Stuff"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="PART_" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="STATE_" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/CodeStyle/XamlStyler/SearchToDriveRoot/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=adorner/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=adorners/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_TYPE/@EntryValue">0</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_ACCESSOR/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64></wpf:ResourceDictionary>

117
README.md
View File

@ -6,21 +6,23 @@
#### Introduce
AtomUI is an implementation of Ant Design based on .NET technology, dedicated to bringing the excellent and efficient design language and experience of Ant Design to the Avalonia/.NET cross-platform desktop software development field.
AtomUI is an implementation of Ant Design based on .NET technology, dedicated to bringing the excellent and efficient
design language and experience of Ant Design to the Avalonia/.NET cross-platform desktop software development field.
Welcome to communicate and give suggestions to AtomUI, thank you for giving the project a Star.
#### Control library completion
##### General
| Control Name | Status |
|:-------------|:-----------|
| Button | Completed ✅|
| PathIcon | Completed ✅|
| SpiltButton | Completed ✅|
| Control Name | Status |
|:-------------|:------------|
| Button | Completed ✅ |
| PathIcon | Completed ✅ |
| SpiltButton | Completed ✅ |
##### Navigation
| Control Name | Status |
|:-------------|:------------|
| Breadcrumb | TODO |
@ -30,6 +32,7 @@ Welcome to communicate and give suggestions to AtomUI, thank you for giving the
| Steps | TODO |
##### Data Entry
| Control Name | Status |
|:----------------|:---------------|
| AutoComplete | TODO |
@ -53,46 +56,48 @@ Welcome to communicate and give suggestions to AtomUI, thank you for giving the
| Upload | Need Review 🤔 |
##### Data Display
| Control Name | Status |
|:---------------|:---------------|
| Avatar | TODO |
| Badge | Completed ✅ |
| Calendar | TODO |
| Card | TODO |
| GroupBox | Completed ✅ |
| Carousel | Developing 💪 |
| Collapse | Completed ✅ |
| Expander | Completed ✅ |
| Descriptions | TODO |
| EmptyIndicator | Completed ✅ |
| Image | TODO |
| ListBox | Completed ✅ |
| Popover | Completed ✅ |
| QRCode | TODO |
| Segmented | Completed ✅ |
| Statistic | TODO |
| Table | TODO |
| TabControl | Completed ✅ |
| Tag | Completed ✅ |
| Timeline | Developing 💪 |
| Tooltip | Completed ✅ |
| Tour | TODO |
| Tree | Completed ✅ |
| Control Name | Status |
|:---------------|:--------------|
| Avatar | TODO |
| Badge | Completed ✅ |
| Calendar | TODO |
| Card | TODO |
| GroupBox | Completed ✅ |
| Carousel | Developing 💪 |
| Collapse | Completed ✅ |
| Expander | Completed ✅ |
| Descriptions | TODO |
| EmptyIndicator | Completed ✅ |
| Image | TODO |
| ListBox | Completed ✅ |
| Popover | Completed ✅ |
| QRCode | TODO |
| Segmented | Completed ✅ |
| Statistic | TODO |
| Table | TODO |
| TabControl | Completed ✅ |
| Tag | Completed ✅ |
| Timeline | Developing 💪 |
| Tooltip | Completed ✅ |
| Tour | TODO |
| Tree | Completed ✅ |
##### Feedback
| Control Name | Status |
|:-------------------|:--------------|
| Alert | Completed ✅ |
| Drawer | Developing 💪 |
| Message | Completed ✅ |
| Modal | Developing 💪 |
| Notification | Completed ✅ |
| Popconfirm | Completed ✅ |
| ProgressBar | Completed ✅ |
| Result | Need Review 🤔 |
| Skeleton | TODO |
| LoadingIndicator | Completed ✅ |
| Watermark | Developing 💪 |
| Control Name | Status |
|:-----------------|:---------------|
| Alert | Completed ✅ |
| Drawer | Developing 💪 |
| Message | Completed ✅ |
| Modal | Developing 💪 |
| Notification | Completed ✅ |
| Popconfirm | Completed ✅ |
| ProgressBar | Completed ✅ |
| Result | Need Review 🤔 |
| Skeleton | TODO |
| LoadingIndicator | Completed ✅ |
| Watermark | Developing 💪 |
#### Some screenshots of the running effect
@ -101,22 +106,35 @@ Welcome to communicate and give suggestions to AtomUI, thank you for giving the
![Button](docs/images/controls/ButtonControl.png)
#### Progress bar control
![Progress](docs/images/controls/ProgressBarControl.png)
#### Slider control
![Slider](docs/images/controls/SliderControl.png)
<div style="height:50px"></div>
#### License Description
The project source code is only free for personal learning and communication or open source projects that follow GPLv3. <strong>Commercial applications (including but not limited to internal company projects, commercial projects developed by individuals using AtomUI, and outsourced projects) require the purchase of a commercial license</strong>. Please contact: Qinpai Software for authorization matters.
The project source code is only free for personal learning and communication or open source projects that follow
GPLv3. <strong>Commercial applications (including but not limited to internal company projects, commercial projects
developed by individuals using AtomUI, and outsourced projects) require the purchase of a commercial license</strong>.
Please contact: Qinpai Software for authorization matters.
#### About the Jiachen Project
<p align="center">
<img src="./docs/images/jiachenjihua.png" width="300" />
</p>
The Jiachen Project (RISC-V Prosperity 2036) was born on New Year's Eve 2024. It was jointly initiated by several domestic RISC-V software and chip teams and has attracted dozens of domestic and foreign companies engaged in RISC-V product and software development to join. We believe that the RISC-V ecosystem is entering the initial stage of unprecedented explosive growth: in 2025, RISC-V may welcome more than 1 million RISC-V application developers, and at the same time RISC-V will enter the world's top 500 supercomputers in 2025 and the top 10 in 2030. We are in a golden age of computer architecture and basic software systems, and the open instruction set architecture has brought a large number of new scientific problems and engineering challenges.
The Jiachen Project (RISC-V Prosperity 2036) was born on New Year's Eve 2024. It was jointly initiated by several
domestic RISC-V software and chip teams and has attracted dozens of domestic and foreign companies engaged in RISC-V
product and software development to join. We believe that the RISC-V ecosystem is entering the initial stage of
unprecedented explosive growth: in 2025, RISC-V may welcome more than 1 million RISC-V application developers, and at
the same time RISC-V will enter the world's top 500 supercomputers in 2025 and the top 10 in 2030. We are in a golden
age of computer architecture and basic software systems, and the open instruction set architecture has brought a large
number of new scientific problems and engineering challenges.
#### About Chinware
@ -124,4 +142,7 @@ The Jiachen Project (RISC-V Prosperity 2036) was born on New Year's Eve 2024. It
<img src="./docs/images/Chinware.png" width="300" />
</p>
Chinware Technologies Ltd. is a technology company dedicated to the development of productivity tool software. Since its inception, it has been determined to deepen its roots in the field of tool software, practice the spirit of continuous improvement in research and development, and strive to launch high-quality productivity tool software to serve developers at home and abroad, improve developers' work efficiency, and create commercial value and social value.
Chinware Technologies Ltd. is a technology company dedicated to the development of productivity tool software. Since its
inception, it has been determined to deepen its roots in the field of tool software, practice the spirit of continuous
improvement in research and development, and strive to launch high-quality productivity tool software to serve
developers at home and abroad, improve developers' work efficiency, and create commercial value and social value.

19
Untitled.DotSettings Normal file
View File

@ -0,0 +1,19 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_TUPLE_COMPONENTS/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_ACCESSOR/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_TYPE/@EntryValue">0</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_ASSIGNMENTS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_VARIABLES/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@ -1,31 +1,31 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TrimMode>copyused</TrimMode>
<BuiltInComInteropSupport>false</BuiltInComInteropSupport>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TrimMode>copyused</TrimMode>
<BuiltInComInteropSupport>false</BuiltInComInteropSupport>
<!-- 'bin/ref/' https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/compiler-options/output#producereferenceassembly -->
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<!-- 'net6.0' https://learn.microsoft.com/zh-cn/dotnet/core/project-sdk/msbuild-props#appendtargetframeworktooutputpath -->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<!-- 'win-x64' https://learn.microsoft.com/zh-cn/dotnet/core/project-sdk/msbuild-props#appendruntimeidentifiertooutputpath -->
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<!-- 'bin/ref/' https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/compiler-options/output#producereferenceassembly -->
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<!-- 'net6.0' https://learn.microsoft.com/zh-cn/dotnet/core/project-sdk/msbuild-props#appendtargetframeworktooutputpath -->
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<!-- 'win-x64' https://learn.microsoft.com/zh-cn/dotnet/core/project-sdk/msbuild-props#appendruntimeidentifiertooutputpath -->
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<IsTestProject Condition="$(MSBuildProjectFullPath.Contains('test')) and ($(MSBuildProjectName.EndsWith('.Tests')) or $(MSBuildProjectName.EndsWith('.TestBase')))">true</IsTestProject>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<NoWarn>$(NoWarn);CS1591;CS0436;CS7035</NoWarn>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<IsTestProject Condition="$(MSBuildProjectFullPath.Contains('test')) and ($(MSBuildProjectName.EndsWith('.Tests')) or $(MSBuildProjectName.EndsWith('.TestBase')))">true</IsTestProject>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<NoWarn>$(NoWarn);CS1591;CS0436;CS7035</NoWarn>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<!-- enable private APIs -->
<AvaloniaAccessUnstablePrivateApis>true</AvaloniaAccessUnstablePrivateApis>
<!-- Mind to specify the exact Avalonia version needed for your package to work -->
<Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>true</Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>
</PropertyGroup>
<!-- enable private APIs -->
<AvaloniaAccessUnstablePrivateApis>true</AvaloniaAccessUnstablePrivateApis>
<!-- Mind to specify the exact Avalonia version needed for your package to work -->
<Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>true</Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>
</PropertyGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);INTERNAL_USING</DefineConstants>
</PropertyGroup>
<DefineConstants>$(DefineConstants);INTERNAL_USING</DefineConstants>
</PropertyGroup>
</Project>

View File

@ -1,33 +1,33 @@
<Project>
<PropertyGroup>
<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">True</GeneratePackageOnBuild>
<PropertyGroup>
<GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">True</GeneratePackageOnBuild>
<PackageId>$(MSBuildProjectName)</PackageId>
<!--Nuget-->
<Title>AtomUI</Title>
<Author>Chinware Technologies Ltd.</Author>
<Authors>$(Author)</Authors>
<Description>AtomUI is an implementation of Ant Design based on .NET technology, and is committed to bringing Ant Design's excellent and efficient design language and experience to the Avalonia/.NET cross-platform desktop software development field.</Description>
<PackageTags>avalonia;antdesign;ui;control</PackageTags>
<ProjectUrl>https://atomui.net</ProjectUrl>
<RepositoryUrl>https://github.com/chinware/AtomUI</RepositoryUrl>
<PackageProjectUrl>https://atomui.net</PackageProjectUrl>
<Company>Chinware Technologies Ltd.</Company>
<Copyright>Copyright ©2018-2024, Chinware Technologies Ltd, All Rights Reserved.</Copyright>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>$(NugetPackageVersion)</Version>
</PropertyGroup>
<PackageId>$(MSBuildProjectName)</PackageId>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)..\logo.png" Visible="False" Pack="True" PackagePath="\"/>
<None Include="$(MSBuildThisFileDirectory)..\LICENSE" Visible="False" Pack="True" PackagePath="\"/>
<None Include="$(MSBuildThisFileDirectory)..\README.md" Visible="False" Pack="True" PackagePath="\"/>
</ItemGroup>
<!--Nuget-->
<Title>AtomUI</Title>
<Author>Chinware Technologies Ltd.</Author>
<Authors>$(Author)</Authors>
<Description>AtomUI is an implementation of Ant Design based on .NET technology, and is committed to bringing Ant Design's excellent and efficient design language and experience to the Avalonia/.NET cross-platform desktop software development field.</Description>
<PackageTags>avalonia;antdesign;ui;control</PackageTags>
<ProjectUrl>https://atomui.net</ProjectUrl>
<RepositoryUrl>https://github.com/chinware/AtomUI</RepositoryUrl>
<PackageProjectUrl>https://atomui.net</PackageProjectUrl>
<Company>Chinware Technologies Ltd.</Company>
<Copyright>Copyright ©2018-2024, Chinware Technologies Ltd, All Rights Reserved.</Copyright>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>$(NugetPackageVersion)</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)..\logo.png" Visible="False" Pack="True" PackagePath="\"/>
<None Include="$(MSBuildThisFileDirectory)..\LICENSE" Visible="False" Pack="True" PackagePath="\"/>
<None Include="$(MSBuildThisFileDirectory)..\README.md" Visible="False" Pack="True" PackagePath="\"/>
</ItemGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<OutputPath>$(MSBuildThisFileDirectory)..\_output\App\$(Configuration)\$(MSBuildProjectName)\</OutputPath>
<OutputPath>$(MSBuildThisFileDirectory)..\_output\App\$(Configuration)\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</PropertyGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<OutputPath>$(ProjectDir)bin\$(Configuration)\</OutputPath>
<OutputPath>$(ProjectDir)bin\$(Configuration)\</OutputPath>
</PropertyGroup>
</PropertyGroup>
</Project>

View File

@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<PackageOutputPath>$(MSBuildThisFileDirectory)..\_output\Nuget\</PackageOutputPath>
<OutputPath>$(MSBuildThisFileDirectory)..\_output\Bin\$(Configuration)\</OutputPath>
<PackageOutputPath>$(MSBuildThisFileDirectory)..\_output\Nuget\</PackageOutputPath>
<OutputPath>$(MSBuildThisFileDirectory)..\_output\Bin\$(Configuration)\</OutputPath>
</PropertyGroup>
</PropertyGroup>
</Project>

View File

@ -1,15 +1,15 @@
<Project>
<PropertyGroup>
<PropertyGroup>
<NoWarn>$(NoWarn);CS7035</NoWarn>
<NoWarn>$(NoWarn);CS7035</NoWarn>
<AvaloniaVersionThatLibrariesUsed>11.1.2</AvaloniaVersionThatLibrariesUsed>
<AvaloniaVersionThatSampleUsed>11.1.2</AvaloniaVersionThatSampleUsed>
<LibVersion>0.0.1</LibVersion>
<NugetPackageVersion>$(LibVersion)-local.1</NugetPackageVersion>
<NugetPackageVersion>$(LibVersion)-preview.1</NugetPackageVersion>
<FileVersion>$([System.DateTime]::Now.ToString("yyyy.MM.dd HH:mm:ss"))</FileVersion>
<AssemblyVersion>$(LibVersion)</AssemblyVersion>
<AvaloniaVersionThatLibrariesUsed>11.1.2</AvaloniaVersionThatLibrariesUsed>
<AvaloniaVersionThatSampleUsed>11.1.2</AvaloniaVersionThatSampleUsed>
<LibVersion>0.0.1</LibVersion>
<NugetPackageVersion>$(LibVersion)-local.1</NugetPackageVersion>
<NugetPackageVersion>$(LibVersion)-preview.1</NugetPackageVersion>
<FileVersion>$([System.DateTime]::Now.ToString("yyyy.MM.dd HH:mm:ss"))</FileVersion>
<AssemblyVersion>$(LibVersion)</AssemblyVersion>
</PropertyGroup>
</PropertyGroup>
</Project>

View File

@ -44,9 +44,13 @@ public class ShowCasePanel : Control
{
var control = Children[i];
if (i % 2 == 0)
{
_leftContainer.Children.Add(control);
}
else
{
_rightContainer.Children.Add(control);
}
}
var scrollView = new ScrollViewer

View File

@ -30,6 +30,9 @@ public class ColorItemControl : TemplatedControl
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
if (DataContext is ColorItemViewModel v) WeakReferenceMessenger.Default.Send(v);
if (DataContext is ColorItemViewModel v)
{
WeakReferenceMessenger.Default.Send(v);
}
}
}

View File

@ -32,7 +32,10 @@ public class IconGallery : TemplatedControl
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
if (DataContext is ColorItemViewModel v) WeakReferenceMessenger.Default.Send(v);
if (DataContext is ColorItemViewModel v)
{
WeakReferenceMessenger.Default.Send(v);
}
}
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
@ -40,7 +43,11 @@ public class IconGallery : TemplatedControl
base.OnAttachedToLogicalTree(e);
if (!_initialized)
{
if (IconThemeType.HasValue) _galleryModel.LoadThemeIcons(IconThemeType.Value);
if (IconThemeType.HasValue)
{
_galleryModel.LoadThemeIcons(IconThemeType.Value);
}
_initialized = true;
}
}

View File

@ -34,13 +34,13 @@ internal class Program
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UseManagedSystemDialogs()
.UsePlatformDetect()
.UseAtomUI()
.UseManagedSystemDialogs()
.UsePlatformDetect()
.UseAtomUI()
#if DEBUG
.UseDevToolsForAvalonia()
.UseDevToolsForAvalonia()
#endif
.UseIconPackage<AntDesignIconPackage>(true)
.With(new Win32PlatformOptions())
.LogToTrace();
.UseIconPackage<AntDesignIconPackage>(true)
.With(new Win32PlatformOptions())
.LogToTrace();
}

View File

@ -32,11 +32,17 @@ public partial class ButtonShowCase : UserControl
private void HandleButtonSizeTypeOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
ButtonSizeType = SizeType.Large;
}
else if (args.Index == 1)
{
ButtonSizeType = SizeType.Middle;
}
else
{
ButtonSizeType = SizeType.Small;
}
}
private void HandleLoadingBtnClick(object? sender, RoutedEventArgs args)

View File

@ -25,13 +25,23 @@ public partial class ButtonSpinnerShowCase : UserControl
{
var value = Array.IndexOf(_spinnerItems, textBlock.Text);
if (e.Direction == SpinDirection.Increase)
{
value++;
}
else
{
value--;
}
if (value < 0)
value = _spinnerItems.Length - 1;
else if (value >= _spinnerItems.Length) value = 0;
{
value = _spinnerItems.Length - 1;
}
else if (value >= _spinnerItems.Length)
{
value = 0;
}
textBlock.Text = _spinnerItems[value];
}
}

View File

@ -26,7 +26,12 @@ public partial class CollapseShowCase : UserControl
private void HandleExpandButtonPosOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
CollapseExpandIconPosition = CollapseExpandIconPosition.Start;
else if (args.Index == 1) CollapseExpandIconPosition = CollapseExpandIconPosition.End;
{
CollapseExpandIconPosition = CollapseExpandIconPosition.Start;
}
else if (args.Index == 1)
{
CollapseExpandIconPosition = CollapseExpandIconPosition.End;
}
}
}

View File

@ -15,9 +15,15 @@ public partial class DrawerShowCase : UserControl
private void Button_OnClick(object? sender, RoutedEventArgs e)
{
if (sender is not Button button) return;
if (sender is not Button button)
{
return;
}
if (Drawer.GetDrawer(button) is not { } drawer) return;
if (Drawer.GetDrawer(button) is not { } drawer)
{
return;
}
drawer.IsOpen = false;
}

View File

@ -35,18 +35,32 @@ public partial class ExpanderShowCase : UserControl
private void HandleExpandButtonPosOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
ToggleIconPosition = ExpanderIconPosition.Start;
else if (args.Index == 1) ToggleIconPosition = ExpanderIconPosition.End;
{
ToggleIconPosition = ExpanderIconPosition.Start;
}
else if (args.Index == 1)
{
ToggleIconPosition = ExpanderIconPosition.End;
}
}
private void HandleExpandDirectionOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
ExpandDirection = ExpandDirection.Down;
}
else if (args.Index == 1)
{
ExpandDirection = ExpandDirection.Up;
}
else if (args.Index == 2)
ExpandDirection = ExpandDirection.Left;
else if (args.Index == 3) ExpandDirection = ExpandDirection.Right;
{
ExpandDirection = ExpandDirection.Left;
}
else if (args.Index == 3)
{
ExpandDirection = ExpandDirection.Right;
}
}
}

View File

@ -28,9 +28,13 @@ public partial class NotificationShowCase : UserControl
if (_basicManager is not null)
{
if (args.Index == 0)
{
_basicManager.IsPauseOnHover = true;
}
else
{
_basicManager.IsPauseOnHover = false;
}
}
}

View File

@ -1,15 +1,13 @@
<UserControl x:Class="AtomUI.Demo.Desktop.ShowCase.Overview"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Avalonia.Markup.Xaml.Converters;assembly=Avalonia.Markup.Xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="1000"
d:DesignWidth="1920"
mc:Ignorable="d">
<UserControl.Resources>
<ResourceDictionary>
</ResourceDictionary>
<ResourceDictionary />
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="Border.CodeBlock">

View File

@ -128,8 +128,12 @@ public partial class ProgressBarShowCase : UserControl
{
ToggleStatus = !ToggleStatus;
if (ToggleStatus)
{
ToggleDisabledText = "Disable";
}
else
{
ToggleDisabledText = "Enable";
}
}
}

View File

@ -18,12 +18,18 @@ public partial class RadioButtonShowCase : UserControl
public static void ToggleDisabledStatus(object arg)
{
var btn = (arg as Button)!;
var btn = (arg as Button)!;
var stackPanel = btn.Parent as StackPanel;
var radioBtn1 = stackPanel?.FindControl<RadioButton>("ToggleDisabledRadioUnChecked");
var radioBtn2 = stackPanel?.FindControl<RadioButton>("ToggleDisabledRadioChecked");
if (radioBtn1 != null) radioBtn1.IsEnabled = !radioBtn1.IsEnabled;
var radioBtn1 = stackPanel?.FindControl<RadioButton>("ToggleDisabledRadioUnChecked");
var radioBtn2 = stackPanel?.FindControl<RadioButton>("ToggleDisabledRadioChecked");
if (radioBtn1 != null)
{
radioBtn1.IsEnabled = !radioBtn1.IsEnabled;
}
if (radioBtn2 != null) radioBtn2.IsEnabled = !radioBtn2.IsEnabled;
if (radioBtn2 != null)
{
radioBtn2.IsEnabled = !radioBtn2.IsEnabled;
}
}
}

View File

@ -19,12 +19,18 @@ public partial class SwitchShowCase : UserControl
public static void ToggleLoadingStatus(object arg)
{
var btn = (arg as Button)!;
var stackPanel = btn.Parent as StackPanel;
var toggleSwitchDefault = stackPanel?.Children[0] as ToggleSwitch;
var toggleSwitchSmall = stackPanel?.Children[1] as ToggleSwitch;
if (toggleSwitchDefault is not null) toggleSwitchDefault.IsLoading = !toggleSwitchDefault.IsLoading;
var btn = (arg as Button)!;
var stackPanel = btn.Parent as StackPanel;
var toggleSwitchDefault = stackPanel?.Children[0] as ToggleSwitch;
var toggleSwitchSmall = stackPanel?.Children[1] as ToggleSwitch;
if (toggleSwitchDefault is not null)
{
toggleSwitchDefault.IsLoading = !toggleSwitchDefault.IsLoading;
}
if (toggleSwitchSmall is not null) toggleSwitchSmall.IsLoading = !toggleSwitchSmall.IsLoading;
if (toggleSwitchSmall is not null)
{
toggleSwitchSmall.IsLoading = !toggleSwitchSmall.IsLoading;
}
}
}

View File

@ -23,8 +23,6 @@ public partial class TabControlShowCase : UserControl
AddTabDemoTabControl.AddTabRequest += HandleTabControlAddTabRequest;
}
#region TabStrip
public static readonly StyledProperty<Dock> PositionTabStripPlacementProperty =
@ -56,8 +54,6 @@ public partial class TabControlShowCase : UserControl
#endregion
#region TabControl
public static readonly StyledProperty<Dock> PositionTabControlPlacementProperty =
@ -89,42 +85,62 @@ public partial class TabControlShowCase : UserControl
#endregion
#region TabStrip
private void HandleTabStripPlacementOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
PositionTabStripPlacement = Dock.Top;
}
else if (args.Index == 1)
{
PositionTabStripPlacement = Dock.Bottom;
}
else if (args.Index == 2)
{
PositionTabStripPlacement = Dock.Left;
}
else
{
PositionTabStripPlacement = Dock.Right;
}
}
private void HandleCardTabStripPlacementOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
PositionCardTabStripPlacement = Dock.Top;
}
else if (args.Index == 1)
{
PositionCardTabStripPlacement = Dock.Bottom;
}
else if (args.Index == 2)
{
PositionCardTabStripPlacement = Dock.Left;
}
else
{
PositionCardTabStripPlacement = Dock.Right;
}
}
private void HandleTabStripSizeTypeOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
SizeTypeTabStrip = SizeType.Small;
}
else if (args.Index == 1)
{
SizeTypeTabStrip = SizeType.Middle;
}
else
{
SizeTypeTabStrip = SizeType.Large;
}
}
private void HandleTabStripAddTabRequest(object? sender, RoutedEventArgs args)
@ -139,42 +155,62 @@ public partial class TabControlShowCase : UserControl
#endregion
#region TabControl
private void HandleTabControlPlacementOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
PositionTabControlPlacement = Dock.Top;
}
else if (args.Index == 1)
{
PositionTabControlPlacement = Dock.Bottom;
}
else if (args.Index == 2)
{
PositionTabControlPlacement = Dock.Left;
}
else
{
PositionTabControlPlacement = Dock.Right;
}
}
private void HandleCardTabControlPlacementOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
PositionCardTabControlPlacement = Dock.Top;
}
else if (args.Index == 1)
{
PositionCardTabControlPlacement = Dock.Bottom;
}
else if (args.Index == 2)
{
PositionCardTabControlPlacement = Dock.Left;
}
else
{
PositionCardTabControlPlacement = Dock.Right;
}
}
private void HandleTabControlSizeTypeOptionCheckedChanged(object? sender, OptionCheckedChangedEventArgs args)
{
if (args.Index == 0)
{
SizeTypeTabControl = SizeType.Small;
}
else if (args.Index == 1)
{
SizeTypeTabControl = SizeType.Middle;
}
else
{
SizeTypeTabControl = SizeType.Large;
}
}
private void HandleTabControlAddTabRequest(object? sender, RoutedEventArgs args)

View File

@ -3,7 +3,7 @@
namespace AtomUI.Demo.Desktop.Utils;
/// <summary>
/// Xaml markup to get the enum values.
/// Xaml markup to get the enum values.
/// </summary>
/// TODO 优化性能时可以考虑缓存类型和列表
public class EnumExtension : MarkupExtension

View File

@ -115,9 +115,13 @@ public class CheckBoxShowCaseModel : ObservableObject
if (ControlledCheckBoxCheckedStatus.HasValue)
{
if (ControlledCheckBoxCheckedStatus.Value)
{
CheckStatusBtnText = "UnCheck";
}
else
{
CheckStatusBtnText = "Check";
}
}
else
{
@ -128,18 +132,28 @@ public class CheckBoxShowCaseModel : ObservableObject
private void SetupEnabledBtnText()
{
if (ControlledCheckBoxEnabledStatus)
{
EnableStatusBtnText = "Disable";
}
else
{
EnableStatusBtnText = "Enable";
}
}
private void SetupControlledCheckBoxText()
{
var checkedText = "UnChecked";
if (ControlledCheckBoxCheckedStatus.HasValue && ControlledCheckBoxCheckedStatus.Value) checkedText = "Checked";
if (ControlledCheckBoxCheckedStatus.HasValue && ControlledCheckBoxCheckedStatus.Value)
{
checkedText = "Checked";
}
var enabledText = "Disabled";
if (ControlledCheckBoxEnabledStatus) enabledText = "Enabled";
var enabledText = "Disabled";
if (ControlledCheckBoxEnabledStatus)
{
enabledText = "Enabled";
}
ControlledCheckBoxText = $"{checkedText}-{enabledText}";
}
@ -163,10 +177,16 @@ public class CheckBoxShowCaseModel : ObservableObject
public void CheckedItemStatusHandler(object arg)
{
if (OrangeCheckedStatus && PearCheckedStatus && AppleCheckedStatus)
{
CheckedAllStatus = true;
}
else if (!OrangeCheckedStatus && !PearCheckedStatus && !AppleCheckedStatus)
{
CheckedAllStatus = false;
}
else
{
CheckedAllStatus = null;
}
}
}

View File

@ -37,7 +37,6 @@ public class DataGridDemoViewModel : ObservableObject
}
}
public class Song
{
public Song(string title, string artist, int m, int s, string album, int countOfComment, int netEaseId)
@ -59,71 +58,70 @@ public class Song
public static List<Song> Songs { get; set; } = new()
{
new("好肚有肚(feat.李玲玉)", "熊猫堂ProducePandas", 2, 50, "A.S.I.A", 730, 1487039339),
new("荒诞秀", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 639, 1487037601),
new("长大", "熊猫堂ProducePandas", 4, 6, "A.S.I.A", 1114, 1487037690),
new("招财猫(feat.纪粹希(G-Tracy))", "熊猫堂ProducePandas", 3, 37, "A.S.I.A", 361, 1487039632),
new("千转", "熊猫堂ProducePandas", 4, 0, "A.S.I.A", 1115, 1477312398),
new("辣辣辣", "熊猫堂ProducePandas", 3, 24, "A.S.I.A", 1873, 1465043716),
new("碎碎念", "熊猫堂ProducePandas", 3, 25, "A.S.I.A", 676, 1474142064),
new("盘他", "熊猫堂ProducePandas", 2, 16, "A.S.I.A", 365, 1481652786),
new("Na Na Na", "熊猫堂ProducePandas", 3, 26, "A.S.I.A", 312, 1469022662),
new("Indigo", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 137, 1487039517),
new("饕餮人间", "熊猫堂ProducePandas", 3, 20, "饕餮人间", 1295, 1499584605),
new("七步咙咚呛", "熊猫堂ProducePandas", 3, 10, "七步咙咚呛", 175, 1809095152),
new("大惊小怪", "熊猫堂ProducePandas", 3, 32, "大惊小怪", 10420, 1847477425),
new("工具人", "熊猫堂ProducePandas", 2, 46, "大惊小怪", 1135, 1847476499),
new("以梦为马", "熊猫堂ProducePandas", 4, 19, "大惊小怪", 18361, 1836034373),
new("以梦为马(Piano Version)", "熊猫堂ProducePandas", 3, 4, "大惊小怪", 570, 1847477423),
new("The ONE", "熊猫堂ProducePandas", 2, 58, "The ONE", 1508, 1864329424),
new("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "The ONE", 385, 1864329429),
new("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 19, "以梦为马 (壮志骄阳版)", 161, 1865138896),
new("New Horse", "熊猫堂ProducePandas", 2, 30, "emo了", 643, 1887021307),
new("不例外", "熊猫堂ProducePandas", 3, 31, "emo了", 1818, 1887022665),
new("满意", "熊猫堂ProducePandas", 4, 32, "emo了", 1081, 1882433472),
new("就算与全世界为敌也要跟你在一起", "熊猫堂ProducePandas", 3, 32, "emo了", 2119, 1881759960),
new("The ONE", "熊猫堂ProducePandas", 2, 58, "emo了", 67, 1887022648),
new("口香糖", "熊猫堂ProducePandas", 3, 10, "emo了", 2181, 1885502254),
new("Suuuuuuper Mario", "熊猫堂ProducePandas", 3, 32, "emo了", 1010, 1887021318),
new("饕餮人间", "熊猫堂ProducePandas", 3, 22, "emo了", 109, 1887021320),
new("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 21, "emo了", 34, 1887022666),
new("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "emo了", 27, 1887022646),
new("满意(DJheap九天版)", "熊猫堂ProducePandas", 4, 31, "emo了", 31, 1901605941),
new("一眼万年", "熊猫堂ProducePandas", 3, 54, "一眼万年", 20, 1922599361),
new("冲刺", "熊猫堂ProducePandas", 3, 49, "冲刺吧", 1006, 1932878194),
new("滴答滴", "熊猫堂ProducePandas", 2, 30, "爱的赏味期限", 86, 1957515790),
new("热带季风", "熊猫堂ProducePandas", 2, 45, "爱的赏味期限", 212, 1957514964),
new("渣", "熊猫堂ProducePandas", 3, 28, "爱的赏味期限", 22, 1957514965),
new("独特", "熊猫堂ProducePandas", 3, 33, "爱的赏味期限", 62, 1957514966),
new("雨后", "熊猫堂ProducePandas", 4, 15, "爱的赏味期限", 23, 1957514967),
new("然后然后", "熊猫堂ProducePandas", 3, 50, "爱的赏味期限", 108, 1957514968),
new("丢", "熊猫堂ProducePandas", 3, 26, "爱的赏味期限", 30, 1957515792),
new("热带疾风(FACEVOID桃心连哥 Remix)", "熊猫堂ProducePandas", 3, 23, "爱的赏味期限", 55, 1957515793),
new("COSMIC ANTHEM -Japanese Ver.-", "熊猫堂ProducePandas", 3, 11, "COSMIC ANTHEM / 手紙", 0, 1977171493),
new("手紙 (「長大-You Raise Me Up-」-Japanese Ver.-)", "熊猫堂ProducePandas", 4, 11, "COSMIC ANTHEM / 手紙", 0,
new Song("好肚有肚(feat.李玲玉)", "熊猫堂ProducePandas", 2, 50, "A.S.I.A", 730, 1487039339),
new Song("荒诞秀", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 639, 1487037601),
new Song("长大", "熊猫堂ProducePandas", 4, 6, "A.S.I.A", 1114, 1487037690),
new Song("招财猫(feat.纪粹希(G-Tracy))", "熊猫堂ProducePandas", 3, 37, "A.S.I.A", 361, 1487039632),
new Song("千转", "熊猫堂ProducePandas", 4, 0, "A.S.I.A", 1115, 1477312398),
new Song("辣辣辣", "熊猫堂ProducePandas", 3, 24, "A.S.I.A", 1873, 1465043716),
new Song("碎碎念", "熊猫堂ProducePandas", 3, 25, "A.S.I.A", 676, 1474142064),
new Song("盘他", "熊猫堂ProducePandas", 2, 16, "A.S.I.A", 365, 1481652786),
new Song("Na Na Na", "熊猫堂ProducePandas", 3, 26, "A.S.I.A", 312, 1469022662),
new Song("Indigo", "熊猫堂ProducePandas", 3, 15, "A.S.I.A", 137, 1487039517),
new Song("饕餮人间", "熊猫堂ProducePandas", 3, 20, "饕餮人间", 1295, 1499584605),
new Song("七步咙咚呛", "熊猫堂ProducePandas", 3, 10, "七步咙咚呛", 175, 1809095152),
new Song("大惊小怪", "熊猫堂ProducePandas", 3, 32, "大惊小怪", 10420, 1847477425),
new Song("工具人", "熊猫堂ProducePandas", 2, 46, "大惊小怪", 1135, 1847476499),
new Song("以梦为马", "熊猫堂ProducePandas", 4, 19, "大惊小怪", 18361, 1836034373),
new Song("以梦为马(Piano Version)", "熊猫堂ProducePandas", 3, 4, "大惊小怪", 570, 1847477423),
new Song("The ONE", "熊猫堂ProducePandas", 2, 58, "The ONE", 1508, 1864329424),
new Song("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "The ONE", 385, 1864329429),
new Song("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 19, "以梦为马 (壮志骄阳版)", 161, 1865138896),
new Song("New Horse", "熊猫堂ProducePandas", 2, 30, "emo了", 643, 1887021307),
new Song("不例外", "熊猫堂ProducePandas", 3, 31, "emo了", 1818, 1887022665),
new Song("满意", "熊猫堂ProducePandas", 4, 32, "emo了", 1081, 1882433472),
new Song("就算与全世界为敌也要跟你在一起", "熊猫堂ProducePandas", 3, 32, "emo了", 2119, 1881759960),
new Song("The ONE", "熊猫堂ProducePandas", 2, 58, "emo了", 67, 1887022648),
new Song("口香糖", "熊猫堂ProducePandas", 3, 10, "emo了", 2181, 1885502254),
new Song("Suuuuuuper Mario", "熊猫堂ProducePandas", 3, 32, "emo了", 1010, 1887021318),
new Song("饕餮人间", "熊猫堂ProducePandas", 3, 22, "emo了", 109, 1887021320),
new Song("以梦为马 (壮志骄阳版)", "熊猫堂ProducePandas", 4, 21, "emo了", 34, 1887022666),
new Song("The ONE(日文版)", "熊猫堂ProducePandas", 2, 57, "emo了", 27, 1887022646),
new Song("满意(DJheap九天版)", "熊猫堂ProducePandas", 4, 31, "emo了", 31, 1901605941),
new Song("一眼万年", "熊猫堂ProducePandas", 3, 54, "一眼万年", 20, 1922599361),
new Song("冲刺", "熊猫堂ProducePandas", 3, 49, "冲刺吧", 1006, 1932878194),
new Song("滴答滴", "熊猫堂ProducePandas", 2, 30, "爱的赏味期限", 86, 1957515790),
new Song("热带季风", "熊猫堂ProducePandas", 2, 45, "爱的赏味期限", 212, 1957514964),
new Song("渣", "熊猫堂ProducePandas", 3, 28, "爱的赏味期限", 22, 1957514965),
new Song("独特", "熊猫堂ProducePandas", 3, 33, "爱的赏味期限", 62, 1957514966),
new Song("雨后", "熊猫堂ProducePandas", 4, 15, "爱的赏味期限", 23, 1957514967),
new Song("然后然后", "熊猫堂ProducePandas", 3, 50, "爱的赏味期限", 108, 1957514968),
new Song("丢", "熊猫堂ProducePandas", 3, 26, "爱的赏味期限", 30, 1957515792),
new Song("热带疾风(FACEVOID桃心连哥 Remix)", "熊猫堂ProducePandas", 3, 23, "爱的赏味期限", 55, 1957515793),
new Song("COSMIC ANTHEM -Japanese Ver.-", "熊猫堂ProducePandas", 3, 11, "COSMIC ANTHEM / 手紙", 0, 1977171493),
new Song("手紙 (「長大-You Raise Me Up-」-Japanese Ver.-)", "熊猫堂ProducePandas", 4, 11, "COSMIC ANTHEM / 手紙", 0,
1977171494),
new("COSMIC ANTHEM -Chinese Ver.-", "熊猫堂ProducePandas", 3, 31, "COSMIC ANTHEM / 手紙", 0, 1977172202),
new("世界晚安", "熊猫堂ProducePandas", 2, 59, "世界晚安", 652, 1985063377),
new("世界晚安(泰文版)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 134, 1987842504),
new("世界晚安(钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 76, 1990475933),
new("世界晚安(泰文钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 29, 1990475934),
new("世界晚安(DJ沈念版)", "熊猫堂ProducePandas", 3, 9, "世界晚安", 34, 2014263184),
new("世界晚安(钢琴配乐)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 11, 2014263185),
new("明年也要好好长大", "熊猫堂ProducePandas", 3, 12, "明年也要好好长大", 0, 2010515162),
new("320万年前DJ沈念版", "熊猫堂ProducePandas", 3, 21, "320万年前", 8, 2055888636),
new("320万年前", "熊猫堂ProducePandas", 3, 7, "W.O.R.L.D.", 329, 2049770469),
new("隐德来希", "熊猫堂ProducePandas", 3, 3, "W.O.R.L.D.", 594, 2061317924),
new("孔明", "熊猫堂ProducePandas", 3, 59, "W.O.R.L.D.", 91, 2063175274),
new("锦鲤卟噜噜", "熊猫堂ProducePandas", 3, 5, "W.O.R.L.D.", 67, 2059208262),
new("指鹿为马", "熊猫堂ProducePandas", 3, 12, "W.O.R.L.D.", 74, 2063175272),
new("热带季风Remix", "熊猫堂ProducePandas", 3, 22, "W.O.R.L.D.", 23, 2063173319),
new("加州梦境", "熊猫堂ProducePandas", 2, 56, "W.O.R.L.D.", 1662, 2063173324),
new("渐近自由", "熊猫堂ProducePandas", 4, 19, "W.O.R.L.D.", 124, 2063173321),
new("世界所有的烂漫", "熊猫堂ProducePandas", 3, 30, "W.O.R.L.D.", 335, 2053388775)
new Song("COSMIC ANTHEM -Chinese Ver.-", "熊猫堂ProducePandas", 3, 31, "COSMIC ANTHEM / 手紙", 0, 1977172202),
new Song("世界晚安", "熊猫堂ProducePandas", 2, 59, "世界晚安", 652, 1985063377),
new Song("世界晚安(泰文版)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 134, 1987842504),
new Song("世界晚安(钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 76, 1990475933),
new Song("世界晚安(泰文钢琴版)", "熊猫堂ProducePandas", 3, 2, "世界晚安", 29, 1990475934),
new Song("世界晚安(DJ沈念版)", "熊猫堂ProducePandas", 3, 9, "世界晚安", 34, 2014263184),
new Song("世界晚安(钢琴配乐)", "熊猫堂ProducePandas", 2, 59, "世界晚安", 11, 2014263185),
new Song("明年也要好好长大", "熊猫堂ProducePandas", 3, 12, "明年也要好好长大", 0, 2010515162),
new Song("320万年前DJ沈念版", "熊猫堂ProducePandas", 3, 21, "320万年前", 8, 2055888636),
new Song("320万年前", "熊猫堂ProducePandas", 3, 7, "W.O.R.L.D.", 329, 2049770469),
new Song("隐德来希", "熊猫堂ProducePandas", 3, 3, "W.O.R.L.D.", 594, 2061317924),
new Song("孔明", "熊猫堂ProducePandas", 3, 59, "W.O.R.L.D.", 91, 2063175274),
new Song("锦鲤卟噜噜", "熊猫堂ProducePandas", 3, 5, "W.O.R.L.D.", 67, 2059208262),
new Song("指鹿为马", "熊猫堂ProducePandas", 3, 12, "W.O.R.L.D.", 74, 2063175272),
new Song("热带季风Remix", "熊猫堂ProducePandas", 3, 22, "W.O.R.L.D.", 23, 2063173319),
new Song("加州梦境", "熊猫堂ProducePandas", 2, 56, "W.O.R.L.D.", 1662, 2063173324),
new Song("渐近自由", "熊猫堂ProducePandas", 4, 19, "W.O.R.L.D.", 124, 2063173321),
new Song("世界所有的烂漫", "熊猫堂ProducePandas", 3, 30, "W.O.R.L.D.", 335, 2053388775)
};
}
public class SongViewModel : ObservableObject
{
private string? _album;

View File

@ -21,7 +21,6 @@ public class PaletteMetaItem
}
}
public class PaletteDemoViewModel : ObservableObject
{
private readonly PaletteMetaItem[] _presetPaletteInfos =
@ -156,7 +155,6 @@ public class PaletteDemoViewModel : ObservableObject
}
}
public class ColorGroupViewModel : ObservableObject
{
private ObservableCollection<ColorListViewModel>? _colorList;
@ -168,7 +166,6 @@ public class ColorGroupViewModel : ObservableObject
}
}
public class ColorListViewModel : ObservableObject
{
private ObservableCollection<ColorItemViewModel>? _colors;
@ -196,7 +193,6 @@ public class ColorListViewModel : ObservableObject
}
}
public class ColorItemViewModel : ObservableObject
{
private IBrush _brush = null!;
@ -213,9 +209,13 @@ public class ColorItemViewModel : ObservableObject
Brush = brush;
Hex = brush.ToString()!.ToUpperInvariant();
if ((light && index < 5) || (!light && index >= 5))
{
TextBrush = Brushes.Black;
}
else
{
TextBrush = Brushes.White;
}
}
public IBrush Brush

View File

@ -29,7 +29,6 @@ public class IconInfoItemModel : ObservableObject
}
}
public class IconGalleryModel : ObservableObject
{
private readonly IconThemeType? _iconThemeType;
@ -39,7 +38,10 @@ public class IconGalleryModel : ObservableObject
public IconGalleryModel(IconThemeType? iconThemeType = null)
{
_iconThemeType = iconThemeType;
if (_iconThemeType.HasValue) LoadThemeIcons(_iconThemeType.Value);
if (_iconThemeType.HasValue)
{
LoadThemeIcons(_iconThemeType.Value);
}
}
public ObservableCollection<IconInfoItemModel>? IconInfos
@ -51,7 +53,10 @@ public class IconGalleryModel : ObservableObject
public void LoadThemeIcons(IconThemeType iconThemeType)
{
var iconPackage = IconManager.Current.GetIconProvider<AntDesignIconPackage>();
if (iconPackage is null) return;
if (iconPackage is null)
{
return;
}
IconInfos = new ObservableCollection<IconInfoItemModel>();
var iconInfos = iconPackage.GetIconInfos(iconThemeType);

View File

@ -11,7 +11,6 @@ public enum TextDecorationLine
LineThrough
}
public enum LineStyle
{
Solid,
@ -21,7 +20,6 @@ public enum LineStyle
Wavy
}
public enum Direction
{
Left,
@ -30,7 +28,6 @@ public enum Direction
Bottom
}
public enum Corner
{
None = 0x00,
@ -41,7 +38,6 @@ public enum Corner
All = TopLeft | TopRight | BottomLeft | BottomRight
}
public enum SizeType
{
Large,
@ -49,7 +45,6 @@ public enum SizeType
Small
}
// 文本修饰信息定义
// 类似 CSS text-decoration
public class TextDecorationInfo
@ -60,7 +55,6 @@ public class TextDecorationInfo
public int Thickness { get; set; } = 1;
}
public enum ColorNameFormat
{
HexRgb,

View File

@ -6,18 +6,26 @@ namespace AtomUI.Data;
public static class BindUtils
{
public static IDisposable RelayBind(AvaloniaObject source, AvaloniaProperty sourceProperty, AvaloniaObject target,
AvaloniaProperty? targetProperty = null,
BindingMode mode = BindingMode.Default)
AvaloniaProperty? targetProperty = null,
BindingMode mode = BindingMode.Default)
{
targetProperty ??= sourceProperty;
var registry = AvaloniaPropertyRegistry.Instance;
if (!sourceProperty.IsAttached)
{
if (!registry.IsRegistered(source.GetType(), sourceProperty))
{
throw new ArgumentException($"Relay source property is not registered for: {source.GetType().Name}.");
}
}
if (!targetProperty.IsAttached)
{
if (!registry.IsRegistered(target.GetType(), targetProperty))
{
throw new ArgumentException($"Relay target property is not registered for: {target.GetType().Name}.");
}
}
var descriptor = new IndexerDescriptor
{
@ -30,17 +38,22 @@ public static class BindUtils
}
public static IDisposable RelayBind<TSource, TResult>(AvaloniaObject source,
AvaloniaProperty<TSource> sourceProperty,
AvaloniaObject target, AvaloniaProperty<TResult> targetProperty,
Func<TSource, TResult> converter,
BindingPriority priority = BindingPriority.Template)
AvaloniaProperty<TSource> sourceProperty,
AvaloniaObject target,
AvaloniaProperty<TResult> targetProperty,
Func<TSource, TResult> converter,
BindingPriority priority = BindingPriority.Template)
{
var registry = AvaloniaPropertyRegistry.Instance;
if (!registry.IsRegistered(source.GetType(), sourceProperty))
{
throw new ArgumentException($"Relay source property is not registered for: {source.GetType().Name}.");
}
if (!registry.IsRegistered(target.GetType(), targetProperty))
{
throw new ArgumentException($"Relay target property is not registered for: {target.GetType().Name}.");
}
return target.Bind(targetProperty, source.GetObservable(sourceProperty, converter), priority);
}

View File

@ -15,7 +15,11 @@ internal static class XYFocusHelpers
XYFocusNavigationModes modes,
KeyDeviceType? keyDeviceType)
{
if (!keyDeviceType.HasValue) return true;
if (!keyDeviceType.HasValue)
{
return true;
}
switch (keyDeviceType.GetValueOrDefault())
{
case KeyDeviceType.Keyboard:

View File

@ -30,7 +30,10 @@ internal class TransformTrackingHelper : IDisposable
public void Dispose()
{
if (_visual == null) return;
if (_visual == null)
{
return;
}
UnsubscribeFromParents();
_visual.AttachedToVisualTree -= OnAttachedToVisualTree;
@ -46,7 +49,10 @@ internal class TransformTrackingHelper : IDisposable
{
visual.AttachedToVisualTree += OnAttachedToVisualTree;
visual.DetachedFromVisualTree -= OnDetachedFromVisualTree;
if (visual.GetVisualRoot() is not null) SubscribeToParents();
if (visual.GetVisualRoot() is not null)
{
SubscribeToParents();
}
UpdateMatrix();
}
@ -74,7 +80,11 @@ internal class TransformTrackingHelper : IDisposable
private void UnsubscribeFromParents()
{
foreach (var v in _propertyChangedSubscriptions) v.PropertyChanged -= _propertyChangedHandler;
foreach (var v in _propertyChangedSubscriptions)
{
v.PropertyChanged -= _propertyChangedHandler;
}
_propertyChangedSubscriptions.Clear();
}
@ -82,7 +92,9 @@ internal class TransformTrackingHelper : IDisposable
{
Matrix? matrix = null;
if (_visual != null && _visual.GetVisualRoot() != null)
{
matrix = _visual.TransformToVisual((Visual)_visual.GetVisualRoot()!);
}
if (Matrix != matrix)
{
@ -99,7 +111,10 @@ internal class TransformTrackingHelper : IDisposable
private void EnqueueForUpdate()
{
if (_queuedForUpdate) return;
if (_queuedForUpdate)
{
return;
}
_queuedForUpdate = true;
var priority = (DispatcherPriority)AfterRenderFieldInfo.GetValue(null)!;
@ -109,7 +124,10 @@ internal class TransformTrackingHelper : IDisposable
private void PropertyChangedHandler(object? sender, AvaloniaPropertyChangedEventArgs e)
{
e.TryGetProperty<bool>("IsEffectiveValueChange", out var isEffectiveValueChange);
if (isEffectiveValueChange && e.Property == Visual.BoundsProperty) EnqueueForUpdate();
if (isEffectiveValueChange && e.Property == Visual.BoundsProperty)
{
EnqueueForUpdate();
}
}
private void OnDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs visualTreeAttachmentEventArgs)

View File

@ -13,10 +13,10 @@ public static class BoxShadowExtensions
var spreadRadius = boxShadow.Spread;
var value = Math.Max(blurRadius + spreadRadius, 0.0); // 可以正负抵消
var left = Math.Max(value - offsetX, 0.0);
var right = Math.Max(value + offsetX, 0.0);
var top = Math.Max(value - offsetY, 0.0);
var bottom = Math.Max(value + offsetY, 0.0);
var left = Math.Max(value - offsetX, 0.0);
var right = Math.Max(value + offsetX, 0.0);
var top = Math.Max(value - offsetY, 0.0);
var bottom = Math.Max(value + offsetY, 0.0);
return new Thickness(left, top, right, bottom);
}

View File

@ -108,7 +108,7 @@ public static class ColorExtensions
}
/// <summary>
/// Returns the perceived brightness of the color, from 0-255.
/// Returns the perceived brightness of the color, from 0-255.
/// </summary>
/// <param name="color"></param>
/// <returns></returns>
@ -118,7 +118,7 @@ public static class ColorExtensions
}
/// <summary>
/// Returns the perceived luminance of a color, from 0-1.
/// Returns the perceived luminance of a color, from 0-1.
/// </summary>
/// <returns></returns>
public static double GetLuminance(this Color color)
@ -131,24 +131,37 @@ public static class ColorExtensions
double g = 0;
double b = 0;
if (MathUtils.LessThanOrClose(rsRGB, 0.03928))
{
r = rsRGB / 12.92;
}
else
// eslint-disable-next-line prefer-exponentiation-operator
{
r = Math.Pow((rsRGB + 0.055) / 1.055, 2.4);
}
if (gsRGB <= 0.03928)
{
g = gsRGB / 12.92;
}
else
// eslint-disable-next-line prefer-exponentiation-operator
{
g = Math.Pow((gsRGB + 0.055) / 1.055, 2.4);
}
if (bsRGB <= 0.03928)
{
b = bsRGB / 12.92;
}
else
// eslint-disable-next-line prefer-exponentiation-operator
{
b = Math.Pow((bsRGB + 0.055) / 1.055, 2.4);
}
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

View File

@ -9,35 +9,31 @@ public enum WCAG2Level
AAA
}
public enum WCAG2Size
{
Large,
Small
}
public class WCAG2Parms
{
public WCAG2Level Level { get; set; } = WCAG2Level.AA;
public WCAG2Size Size { get; set; } = WCAG2Size.Small;
}
public class WCAG2FallbackParms : WCAG2Parms
{
public bool IncludeFallbackColors { get; set; }
}
public static class ColorUtils
{
public static Color FromRgbF(double alpha, double red, double green, double blue)
{
return Color.FromArgb((byte)Math.Round(alpha * 255d),
(byte)Math.Round(red * 255d),
(byte)Math.Round(green * 255d),
(byte)Math.Round(blue * 255d));
(byte)Math.Round(red * 255d),
(byte)Math.Round(green * 255d),
(byte)Math.Round(blue * 255d));
}
public static Color FromRgbF(double red, double green, double blue)
@ -123,7 +119,10 @@ public static class ColorUtils
var fG = frontColor.GetGreenF();
var fB = frontColor.GetBlueF();
var originAlpha = frontColor.GetAlphaF();
if (originAlpha < 1d) return frontColor;
if (originAlpha < 1d)
{
return frontColor;
}
var bR = backgroundColor.GetRedF();
var bG = backgroundColor.GetGreenF();
@ -135,7 +134,9 @@ public static class ColorUtils
var g = Math.Round((fG - bG * (1d - fA)) / fA);
var b = Math.Round((fB - bB * (1d - fA)) / fA);
if (IsStableColor(r) && IsStableColor(g) && IsStableColor(b))
{
return FromRgbF(Math.Round(fA * 100d) / 100d, r, g, b);
}
}
// fallback
@ -145,7 +146,10 @@ public static class ColorUtils
public static Color ParseCssRgbColor(string colorExpr)
{
if (TryParseCssRgbColor(colorExpr, out var color)) return color;
if (TryParseCssRgbColor(colorExpr, out var color))
{
return color;
}
throw new FormatException($"Invalid color string: '{colorExpr}'.");
}
@ -153,39 +157,63 @@ public static class ColorUtils
public static bool TryParseCssRgbColor(string? colorExpr, out Color color)
{
color = default;
if (string.IsNullOrEmpty(colorExpr)) return false;
if (string.IsNullOrEmpty(colorExpr))
{
return false;
}
if (colorExpr[0] == '#') return Color.TryParse(colorExpr, out color);
if (colorExpr[0] == '#')
{
return Color.TryParse(colorExpr, out color);
}
var isRgba = colorExpr.StartsWith("rgba", StringComparison.InvariantCultureIgnoreCase);
var isRgb = false;
if (!isRgba) isRgb = colorExpr.StartsWith("rgb", StringComparison.InvariantCultureIgnoreCase);
var isRgba = colorExpr.StartsWith("rgba", StringComparison.InvariantCultureIgnoreCase);
var isRgb = false;
if (!isRgba)
{
isRgb = colorExpr.StartsWith("rgb", StringComparison.InvariantCultureIgnoreCase);
}
if (isRgb || isRgba)
{
var leftParen = colorExpr.IndexOf('(');
var rightParen = colorExpr.IndexOf(')');
if (leftParen == -1 || rightParen == -1) return false;
if (leftParen == -1 || rightParen == -1)
{
return false;
}
var parts = new List<string>(colorExpr.Substring(leftParen + 1, rightParen - leftParen - 1)
.Split(',', StringSplitOptions.RemoveEmptyEntries));
.Split(',', StringSplitOptions.RemoveEmptyEntries));
if (isRgb)
{
if (parts.Count != 3) return false;
if (parts.Count != 3)
{
return false;
}
parts.Add("255");
}
else
{
if (parts.Count != 4) return false;
if (parts.Count != 4)
{
return false;
}
}
var rgbaValues = new List<int>();
foreach (var part in parts)
{
if (int.TryParse(part, out var partValue))
{
rgbaValues.Add(partValue);
}
else
{
return false;
}
}
color = Color.FromArgb((byte)rgbaValues[0], (byte)rgbaValues[1], (byte)rgbaValues[2], (byte)rgbaValues[3]);
return true;
@ -197,8 +225,8 @@ public static class ColorUtils
/// Readability Functions
/// ---------------------
/// <http:// www.w3.org/ TR/2008/ REC-WCAG20-20081211/# contrast-ratiodef ( WCAG Version 2)
/// AKA ` contrast`
/// Analyze the 2 colors and returns the color contrast defined by ( WCAG Version
/// AKA ` contrast`
/// Analyze the 2 colors and returns the color contrast defined by ( WCAG Version
/// 2
/// )
public static double Readability(Color color1, Color color2)
@ -222,14 +250,20 @@ public static class ColorUtils
var readabilityLevel = Readability(color1, color2);
if (wcag2.Level == WCAG2Level.AA)
{
if (wcag2.Size == WCAG2Size.Large) return MathUtils.GreaterThanOrClose(readabilityLevel, 3);
if (wcag2.Size == WCAG2Size.Large)
{
return MathUtils.GreaterThanOrClose(readabilityLevel, 3);
}
return MathUtils.GreaterThanOrClose(readabilityLevel, 4.5);
}
if (wcag2.Level == WCAG2Level.AAA)
{
if (wcag2.Size == WCAG2Size.Large) return MathUtils.GreaterThanOrClose(readabilityLevel, 4.5);
if (wcag2.Size == WCAG2Size.Large)
{
return MathUtils.GreaterThanOrClose(readabilityLevel, 4.5);
}
return MathUtils.GreaterThanOrClose(readabilityLevel, 7);
}
@ -272,7 +306,9 @@ public static class ColorUtils
if (IsReadable(baseColor, bestColor!.Value, new WCAG2Parms { Level = args.Level, Size = args.Size }) ||
!args.IncludeFallbackColors)
{
return bestColor;
}
args.IncludeFallbackColors = false;
return MostReadable(baseColor, new List<Color>

View File

@ -13,8 +13,8 @@ public static class CommonShapeBuilder
using var context = checkMark.Open();
var startPoint = new Point(size.Width * 0.25, size.Height * 0.5);
var midPoint = new Point(size.Width * 0.4, size.Height * 0.7);
var endPoint = new Point(size.Width * 0.7, size.Height * 0.3);
var midPoint = new Point(size.Width * 0.4, size.Height * 0.7);
var endPoint = new Point(size.Width * 0.7, size.Height * 0.3);
context.BeginFigure(startPoint, true);
context.LineTo(midPoint);
@ -25,7 +25,7 @@ public static class CommonShapeBuilder
}
/// <summary>
/// 生成一个以矩形中点为圆心,以宽和高最小的一半为半径的且指定角度的圆弧
/// 生成一个以矩形中点为圆心,以宽和高最小的一半为半径的且指定角度的圆弧
/// </summary>
/// <param name="rect"></param>
/// <param name="startAngle"></param>
@ -33,7 +33,10 @@ public static class CommonShapeBuilder
/// <returns></returns>
public static Geometry BuildArc(Rect rect, double startAngle, double sweepAngle)
{
if (MathUtils.IsZero(sweepAngle)) return new StreamGeometry();
if (MathUtils.IsZero(sweepAngle))
{
return new StreamGeometry();
}
var angle1 = MathUtilities.Deg2Rad(startAngle);
var angle2 = angle1 + MathUtilities.Deg2Rad(sweepAngle);
@ -47,7 +50,9 @@ public static class CommonShapeBuilder
if (MathUtils.AreClose(normStart, normEnd) && !MathUtils.AreClose(startAngle, sweepAngle))
// Complete ring.
{
return new EllipseGeometry(rect);
}
// Partial arc.
var deflatedRect = rect;
@ -55,7 +60,7 @@ public static class CommonShapeBuilder
var centerX = rect.Center.X;
var centerY = rect.Center.Y;
var radiusX = deflatedRect.Width / 2;
var radiusX = deflatedRect.Width / 2;
var radiusY = deflatedRect.Height / 2;
var angleGap = RadToNormRad(sweepAngle - startAngle);

View File

@ -7,19 +7,24 @@ namespace AtomUI.Media;
public static class DrawingContextExtensions
{
public static void DrawPilledRect(this DrawingContext context, IBrush? brush, IPen? pen, Rect rect,
Orientation orientation = Orientation.Horizontal,
BoxShadows boxShadows = default)
Orientation orientation = Orientation.Horizontal,
BoxShadows boxShadows = default)
{
double pillRadius;
if (orientation == Orientation.Horizontal)
{
pillRadius = rect.Height / 2;
}
else
{
pillRadius = rect.Width / 2;
}
context.DrawRectangle(brush, pen, rect, pillRadius, pillRadius, boxShadows);
}
public static void DrawArc(this DrawingContext context, IPen? pen,
Rect rect, double startAngle, double sweepAngle)
Rect rect, double startAngle, double sweepAngle)
{
var geometry = CommonShapeBuilder.BuildArc(rect, startAngle, sweepAngle);
context.DrawGeometry(null, pen, geometry);

View File

@ -2,14 +2,14 @@
public static class FontUtils
{
/// <summary>
/// 将 value 的值转换为像素
/// </summary>
/// <param name="value"></param>
/// <param name="fontSize"></param>
/// <param name="renderScaling"></param>
/// <returns></returns>
public static double ConvertEmToPixel(double value, double fontSize, double renderScaling = 1.0)
/// <summary>
/// 将 value 的值转换为像素
/// </summary>
/// <param name="value"></param>
/// <param name="fontSize"></param>
/// <param name="renderScaling"></param>
/// <returns></returns>
public static double ConvertEmToPixel(double value, double fontSize, double renderScaling = 1.0)
{
var fontSizePx = fontSize * value * renderScaling;
return fontSizePx * value;

View File

@ -23,7 +23,7 @@ public static class GeometryUtils
var newY = rect.Y - offsetYChange;
// 计算新的矩形宽度和高度
var newWidth = rect.Width * scaleFactorX;
var newWidth = rect.Width * scaleFactorX;
var newHeight = rect.Height * scaleFactorY;
return new Rect(newX, newY, newWidth, newHeight);
@ -31,7 +31,10 @@ public static class GeometryUtils
public static double CornerRadiusScalarValue(CornerRadius cornerRadius, bool maxWhenNotUniform = true)
{
if (cornerRadius.IsUniform) return cornerRadius.TopLeft;
if (cornerRadius.IsUniform)
{
return cornerRadius.TopLeft;
}
return maxWhenNotUniform
? Math.Max(cornerRadius.TopLeft,

View File

@ -10,7 +10,6 @@ public class TransitionCompletedEventArgs : EventArgs
public bool Status { get; }
}
internal interface INotifyTransitionCompleted
{
public IObservable<bool> CompletedObservable { get; }

View File

@ -7,14 +7,14 @@ public static class InterpolateUtils
public static Color ColorInterpolate(Color fromColor, Color toColor, double progress)
{
var a1 = fromColor.GetAlphaF();
var r1 = fromColor.GetRedF() * a1;
var r1 = fromColor.GetRedF() * a1;
var g1 = fromColor.GetGreenF() * a1;
var b1 = fromColor.GetBlueF() * a1;
var b1 = fromColor.GetBlueF() * a1;
var a2 = toColor.GetAlphaF();
var r2 = toColor.GetRedF() * a2;
var r2 = toColor.GetRedF() * a2;
var g2 = toColor.GetGreenF() * a2;
var b2 = toColor.GetBlueF() * a2;
var b2 = toColor.GetBlueF() * a2;
var r = DoubleInterpolate(r1, r2, progress);
var g = DoubleInterpolate(g1, g2, progress);

View File

@ -6,26 +6,26 @@ namespace AtomUI.Media;
public static class PenUtils
{
/// <summary>
/// Smart reuse and update pen properties.
/// </summary>
/// <param name="pen">Old pen to modify.</param>
/// <param name="brush">The brush used to draw.</param>
/// <param name="thickness">The stroke thickness.</param>
/// <param name="strokeDashArray">The stroke dask array.</param>
/// <param name="strokeDaskOffset">The stroke dask offset.</param>
/// <param name="lineCap">The line cap.</param>
/// <param name="lineJoin">The line join.</param>
/// <param name="miterLimit">The miter limit.</param>
/// <returns>If a new instance was created and visual invalidation required.</returns>
internal static bool TryModifyOrCreate(ref IPen? pen,
IBrush? brush,
double thickness,
IList<double>? strokeDashArray = null,
double strokeDaskOffset = default,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0)
/// <summary>
/// Smart reuse and update pen properties.
/// </summary>
/// <param name="pen">Old pen to modify.</param>
/// <param name="brush">The brush used to draw.</param>
/// <param name="thickness">The stroke thickness.</param>
/// <param name="strokeDashArray">The stroke dask array.</param>
/// <param name="strokeDaskOffset">The stroke dask offset.</param>
/// <param name="lineCap">The line cap.</param>
/// <param name="lineJoin">The line join.</param>
/// <param name="miterLimit">The miter limit.</param>
/// <returns>If a new instance was created and visual invalidation required.</returns>
internal static bool TryModifyOrCreate(ref IPen? pen,
IBrush? brush,
double thickness,
IList<double>? strokeDashArray = null,
double strokeDaskOffset = default,
PenLineCap lineCap = PenLineCap.Flat,
PenLineJoin lineJoin = PenLineJoin.Miter,
double miterLimit = 10.0)
{
var previousPen = pen;
if (brush is null)
@ -39,9 +39,11 @@ public static class PenUtils
// strokeDashArray can be IList (instead of AvaloniaList) in future
// So, if it supports notification - create a mutable DashStyle
{
dashStyle = strokeDashArray is INotifyCollectionChanged
? new DashStyle(strokeDashArray, strokeDaskOffset)
: new ImmutableDashStyle(strokeDashArray, strokeDaskOffset);
}
if (brush is IImmutableBrush immutableBrush && dashStyle is null or ImmutableDashStyle)
{

View File

@ -9,6 +9,6 @@ public class PixelPointTransition : InterpolatingTransitionBase<PixelPoint>
{
var delta = newValue - oldValue;
return new PixelPoint((int)Math.Round(delta.X * progress + oldValue.X),
(int)Math.Round(delta.Y * progress + oldValue.Y));
(int)Math.Round(delta.Y * progress + oldValue.Y));
}
}

View File

@ -8,12 +8,17 @@ public class SolidColorBrushTransition : InterpolatingTransitionBase<IBrush?>
{
protected override IBrush? Interpolate(double progress, IBrush? from, IBrush? to)
{
if (from is null || to is null) return progress >= 0.5 ? to : from;
if (from is null || to is null)
{
return progress >= 0.5 ? to : from;
}
if (from is ISolidColorBrush fromBrush && to is ISolidColorBrush toBrush)
{
return new ImmutableSolidColorBrush(
InterpolateUtils.ColorInterpolate(fromBrush.Color, toBrush.Color, progress),
DoubleInterpolate(progress, from.Opacity, to.Opacity));
}
// TODO 不知道这样返回是否合适
return from;

View File

@ -7,10 +7,10 @@ namespace AtomUI.Media;
public static class TextUtils
{
public static Size CalculateTextSize(string text,
double fontSize,
FontFamily fontFamily,
FontStyle fontStyle = FontStyle.Normal,
FontWeight fontWeight = FontWeight.Normal)
double fontSize,
FontFamily fontFamily,
FontStyle fontStyle = FontStyle.Normal,
FontWeight fontWeight = FontWeight.Normal)
{
var typeface = new Typeface(fontFamily, fontStyle, fontWeight);
using var textLayout = new TextLayout(text, typeface, fontSize, null);

View File

@ -17,7 +17,6 @@ public enum TransitionKind
TransformOperations
}
public record class MotionConfig
{
public MotionConfig(AvaloniaProperty targetProperty, object? startValue = null, object? endValue = null)
@ -35,7 +34,6 @@ public record class MotionConfig
public TransitionKind TransitionKind { get; set; }
}
public abstract class AbstractMotion : AvaloniaObject, IMotion
{
// 定义我们目前支持的动效属性
@ -108,7 +106,7 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
}
/// <summary>
/// 创建动效动画对象
/// 创建动效动画对象
/// </summary>
/// <param name="motionTarget"></param>
/// <returns></returns>
@ -127,7 +125,9 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
{
var transition = _transitions[i];
if (transition is INotifyTransitionCompleted notifyTransitionCompleted)
{
completedObservables[i] = notifyTransitionCompleted.CompletedObservable;
}
}
CompletedObservable =
@ -164,9 +164,13 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
{
TransitionBase transition = default!;
if (config.TransitionKind == TransitionKind.Double)
{
transition = new NotifiableDoubleTransition();
}
else if (config.TransitionKind == TransitionKind.TransformOperations)
{
transition = new NotifiableTransformOperationsTransition();
}
transition.Property = config.Property;
transition.Duration = config.MotionDuration;
@ -176,7 +180,11 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
protected MotionConfig? GetMotionConfig(AvaloniaProperty property)
{
if (_motionConfigs.TryGetValue(property, out var motionConfig)) return motionConfig;
if (_motionConfigs.TryGetValue(property, out var motionConfig))
{
return motionConfig;
}
return null;
}
@ -187,12 +195,12 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
}
/// <summary>
/// 计算顶层动画渲染层的大小
/// 计算顶层动画渲染层的大小
/// </summary>
/// <param name="motionTargetSize">
/// 动画目标控件的大小,如果动画直接调度到控件本身,则是控件本身的大小,如果是顶层动画渲染,那么就是 ghost
/// 的大小,如果有阴影这个大小包含阴影的 thickness
/// 目前的实现没有加一个固定的 Padding
/// 动画目标控件的大小,如果动画直接调度到控件本身,则是控件本身的大小,如果是顶层动画渲染,那么就是 ghost
/// 的大小,如果有阴影这个大小包含阴影的 thickness
/// 目前的实现没有加一个固定的 Padding
/// </param>
/// <returns></returns>
internal virtual Size CalculateSceneSize(Size motionTargetSize)
@ -201,7 +209,7 @@ public abstract class AbstractMotion : AvaloniaObject, IMotion
}
/// <summary>
/// 计算动画层的全局坐标
/// 计算动画层的全局坐标
/// </summary>
/// <param name="motionTargetSize">动画目标控件的大小,包含阴影</param>
/// <param name="motionTargetPosition">动画目标控件的最终全局坐标位置</param>

View File

@ -10,7 +10,11 @@ internal class AnimationTargetPanel : Panel
protected override Size MeasureOverride(Size availableSize)
{
if (InAnimation && _cacheMeasureSize != default) return _cacheMeasureSize;
if (InAnimation && _cacheMeasureSize != default)
{
return _cacheMeasureSize;
}
_cacheMeasureSize = base.MeasureOverride(availableSize);
return _cacheMeasureSize;
}

View File

@ -10,7 +10,7 @@ public class CollapseMotion : AbstractMotion
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
/// <summary>
/// 收起的方向,垂直还是水平方向
/// 收起的方向,垂直还是水平方向
/// </summary>
public Orientation Orientation { get; set; } = Orientation.Vertical;
@ -49,28 +49,35 @@ public class CollapseMotion : AbstractMotion
if (config.Property == MotionHeightProperty)
{
if (!double.IsNaN(motionTarget.Height))
{
config.StartValue = Math.Ceiling(motionTarget.Height);
}
else
{
config.StartValue = Math.Ceiling(motionTarget.DesiredSize.Height);
}
}
else if (config.Property == MotionWidthProperty)
{
if (!double.IsNaN(motionTarget.Width))
{
config.StartValue = Math.Ceiling(motionTarget.Width);
}
else
{
config.StartValue = Math.Ceiling(motionTarget.DesiredSize.Width);
}
}
}
}
public class ExpandMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
public MotionConfig? HeightConfig => GetMotionConfig(MotionHeightProperty);
/// <summary>
/// 展开的方向,垂直还是水平方向
/// 展开的方向,垂直还是水平方向
/// </summary>
public Orientation Orientation { get; set; } = Orientation.Vertical;
@ -109,16 +116,24 @@ public class ExpandMotion : AbstractMotion
if (config.Property == MotionHeightProperty)
{
if (!double.IsNaN(motionTarget.Height))
{
config.EndValue = Math.Ceiling(motionTarget.Height);
}
else
{
config.EndValue = Math.Ceiling(motionTarget.DesiredSize.Height);
}
}
else if (config.Property == MotionWidthProperty)
{
if (!double.IsNaN(motionTarget.Width))
{
config.EndValue = Math.Ceiling(motionTarget.Width);
}
else
{
config.EndValue = Math.Ceiling(motionTarget.DesiredSize.Width);
}
}
}
}

View File

@ -7,8 +7,8 @@ namespace AtomUI.Controls.MotionScene;
public class Director : IDirector
{
private CompositeDisposable? _compositeDisposable;
private readonly Dictionary<IMotionActor, MotionActorState> _states;
private CompositeDisposable? _compositeDisposable;
public Director()
{
@ -18,25 +18,35 @@ public class Director : IDirector
public static IDirector? Instance => AvaloniaLocator.Current.GetService<IDirector>();
/// <summary>
/// 目前的实现暂时一个 Actor 只能投递一次,后面可以实现一个等待队列
/// 目前的实现暂时一个 Actor 只能投递一次,后面可以实现一个等待队列
/// </summary>
/// <param name="actor"></param>
public void Schedule(MotionActor actor)
{
if (_states.ContainsKey(actor)) return;
if (_states.ContainsKey(actor))
{
return;
}
actor.NotifyPostedToDirector();
SceneLayer? sceneLayer = default;
if (actor.DispatchInSceneLayer) sceneLayer = PrepareSceneLayer(actor);
SceneLayer? sceneLayer = default;
if (actor.DispatchInSceneLayer)
{
sceneLayer = PrepareSceneLayer(actor);
}
_compositeDisposable = new CompositeDisposable();
_compositeDisposable.Add(Disposable.Create(sceneLayer, state =>
{
if (sceneLayer is not null)
{
Dispatcher.UIThread.InvokeAsync(async () =>
{
await Task.Delay(300);
sceneLayer.Hide();
sceneLayer.Dispose();
});
}
}));
var state = new MotionActorState(actor, _compositeDisposable);
_states.Add(actor, state);
@ -64,8 +74,10 @@ public class Director : IDirector
private SceneLayer PrepareSceneLayer(MotionActor actor)
{
if (actor.SceneParent is null)
{
throw new ArgumentException(
"When the DispatchInSceneLayer property is true, the SceneParent property cannot be null.");
}
// TODO 这里除了 Popup 这种顶层元素以外,还会不会有其他的顶层元素种类
// 暂时先处理 Popup 这种情况
@ -91,7 +103,9 @@ public class Director : IDirector
actor.NotifyMotionPreStart();
MotionPreStart?.Invoke(this, new MotionEventArgs(actor));
if (actor.Motion.CompletedObservable is null)
{
throw new InvalidOperationException("The CompletedObservable property of the Motion is empty.");
}
// 设置相关的完成检测
_compositeDisposable?.Add(actor.Motion.CompletedObservable.Subscribe(
@ -116,7 +130,11 @@ public class Director : IDirector
{
if (_states.TryGetValue(actor, out var state))
{
if (state.SceneLayer is not null) state.SceneLayer.Opacity = 0;
if (state.SceneLayer is not null)
{
state.SceneLayer.Opacity = 0;
}
actor.NotifyMotionCompleted();
MotionCompleted?.Invoke(this, new MotionEventArgs(actor));
state.Dispose();
@ -124,7 +142,6 @@ public class Director : IDirector
}
}
private class MotionActorState : IDisposable
{
private readonly IDisposable _cleanup;
@ -145,7 +162,6 @@ public class Director : IDirector
}
}
public class MotionEventArgs : EventArgs
{
public MotionActor MotionActor;

View File

@ -22,7 +22,6 @@ public class FadeInMotion : AbstractMotion
}
}
public class FadeOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);

View File

@ -8,7 +8,7 @@ public interface IMotion
public IObservable<bool>? CompletedObservable { get; }
/// <summary>
/// 获取当前动效激活的动画属性列表
/// 获取当前动效激活的动画属性列表
/// </summary>
/// <returns></returns>
public IList<AvaloniaProperty> GetActivatedProperties();

View File

@ -12,8 +12,8 @@ using Avalonia.VisualTree;
namespace AtomUI.MotionScene;
/// <summary>
/// 动效配置类,只要给 Director 提供动效相关信息
/// 动效驱动 Actor 的属性,然后由 Actor 驱动动画控件,防止污染动画控件的 Transitions 配置
/// 动效配置类,只要给 Director 提供动效相关信息
/// 动效驱动 Actor 的属性,然后由 Actor 驱动动画控件,防止污染动画控件的 Transitions 配置
/// </summary>
public class MotionActor : Animatable, IMotionActor
{
@ -31,6 +31,7 @@ public class MotionActor : Animatable, IMotionActor
private static readonly MethodInfo EnableTransitionsMethodInfo;
private static readonly MethodInfo DisableTransitionsMethodInfo;
private readonly Dictionary<AvaloniaProperty, AnimationState> _transitionsMap;
protected Control? _ghost;
protected AbstractMotion _motion;
@ -40,7 +41,6 @@ public class MotionActor : Animatable, IMotionActor
private ITransform? _originRenderTransform;
private RelativePoint _originRenderTransformOrigin;
private double _originWidth;
private readonly Dictionary<AvaloniaProperty, AnimationState> _transitionsMap;
static MotionActor()
{
@ -86,7 +86,7 @@ public class MotionActor : Animatable, IMotionActor
}
/// <summary>
/// 当 DispatchInSceneLayer 为 true 的时候,必须指定一个动画 SceneLayer 的父窗口,最好不要是 Popup
/// 当 DispatchInSceneLayer 为 true 的时候,必须指定一个动画 SceneLayer 的父窗口,最好不要是 Popup
/// </summary>
public TopLevel? SceneParent { get; set; }
@ -97,7 +97,7 @@ public class MotionActor : Animatable, IMotionActor
public bool CompletedStatus { get; internal set; } = true;
/// <summary>
/// 动画实体
/// 动画实体
/// </summary>
public Control MotionTarget { get; set; }
@ -111,7 +111,11 @@ public class MotionActor : Animatable, IMotionActor
var oldValue = args.OldValue;
var newValue = args.NewValue;
var priority = args.Priority;
if (!actor._transitionsMap.ContainsKey(property)) return;
if (!actor._transitionsMap.ContainsKey(property))
{
return;
}
var state = actor._transitionsMap[property];
if (actor.IsAnimating(property) && priority == BindingPriority.Animation)
{
@ -124,7 +128,9 @@ public class MotionActor : Animatable, IMotionActor
{
var transition = state.Transition;
if (transition is INotifyTransitionCompleted notifyTransitionCompleted)
{
notifyTransitionCompleted.NotifyTransitionCompleted(true);
}
}
}
else if (property.PropertyType.IsAssignableTo(typeof(ITransform)))
@ -135,7 +141,9 @@ public class MotionActor : Animatable, IMotionActor
{
var transition = state.Transition;
if (transition is INotifyTransitionCompleted notifyTransitionCompleted)
{
notifyTransitionCompleted.NotifyTransitionCompleted(true);
}
}
}
}
@ -144,10 +152,13 @@ public class MotionActor : Animatable, IMotionActor
public bool IsSupportMotionProperty(AvaloniaProperty property)
{
if (property == AbstractMotion.MotionOpacityProperty ||
property == AbstractMotion.MotionWidthProperty ||
property == AbstractMotion.MotionHeightProperty ||
property == AbstractMotion.MotionWidthProperty ||
property == AbstractMotion.MotionHeightProperty ||
property == AbstractMotion.MotionRenderTransformProperty)
{
return true;
}
return false;
}
@ -161,7 +172,7 @@ public class MotionActor : Animatable, IMotionActor
}
/// <summary>
/// 当在 DispatchInSceneLayer 渲染的时候Ghost 的全局坐标
/// 当在 DispatchInSceneLayer 渲染的时候Ghost 的全局坐标
/// </summary>
/// <returns></returns>
public Point CalculateGhostPosition()
@ -174,9 +185,13 @@ public class MotionActor : Animatable, IMotionActor
{
var parentPoint = MotionTarget.TranslatePoint(new Point(0, 0), visualParent);
if (parentPoint.HasValue)
{
point = parentPoint.Value;
}
else
{
point = MotionTarget.Bounds.Position;
}
}
}
else
@ -193,12 +208,15 @@ public class MotionActor : Animatable, IMotionActor
}
/// <summary>
/// 在这个接口中Actor 根据自己的需求对 sceneLayer 进行设置,主要就是位置和大小
/// 在这个接口中Actor 根据自己的需求对 sceneLayer 进行设置,主要就是位置和大小
/// </summary>
/// <param name="sceneLayer"></param>
public virtual void NotifySceneLayerCreated(SceneLayer sceneLayer)
{
if (!DispatchInSceneLayer) return;
if (!DispatchInSceneLayer)
{
return;
}
var ghost = GetAnimatableGhost();
@ -208,9 +226,13 @@ public class MotionActor : Animatable, IMotionActor
if (ghost.DesiredSize == default)
// Popup may not have been shown yet. Measure content
{
motionTargetSize = LayoutHelper.MeasureChild(ghost, Size.Infinity, new Thickness());
}
else
{
motionTargetSize = ghost.DesiredSize;
}
var sceneSize = _motion.CalculateSceneSize(motionTargetSize);
var scenePosition = _motion.CalculateScenePosition(motionTargetSize, CalculateGhostPosition());
@ -223,7 +245,11 @@ public class MotionActor : Animatable, IMotionActor
BuildGhost();
RelayMotionProperties();
var transitions = new Transitions();
foreach (var transition in _motion.BuildTransitions(GetAnimatableGhost())) transitions.Add(transition);
foreach (var transition in _motion.BuildTransitions(GetAnimatableGhost()))
{
transitions.Add(transition);
}
Transitions = transitions;
}
@ -239,7 +265,7 @@ public class MotionActor : Animatable, IMotionActor
}
/// <summary>
/// 当动画目标控件被添加到动画场景中之后调用,这里需要根据 Motion 的种类设置初始位置和大小
/// 当动画目标控件被添加到动画场景中之后调用,这里需要根据 Motion 的种类设置初始位置和大小
/// </summary>
/// <param name="motionTarget"></param>
public virtual void NotifyMotionTargetAddedToScene(Control motionTarget)
@ -266,11 +292,15 @@ public class MotionActor : Animatable, IMotionActor
internal virtual void NotifyMotionPreStart()
{
if (Transitions is not null)
{
foreach (var transition in Transitions)
{
_transitionsMap.Add(transition.Property, new AnimationState
{
Transition = transition
});
}
}
foreach (var motionConfig in _motion.GetMotionConfigs())
{
@ -305,6 +335,7 @@ public class MotionActor : Animatable, IMotionActor
{
var target = GetAnimatableGhost();
foreach (var motionConfig in _motion.GetMotionConfigs())
{
if (motionConfig.Property == MotionHeightProperty)
{
_originHeight = target.Height;
@ -322,13 +353,14 @@ public class MotionActor : Animatable, IMotionActor
_originRenderTransform = target.RenderTransform;
_originRenderTransformOrigin = target.RenderTransformOrigin;
}
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == MotionWidthProperty ||
change.Property == MotionHeightProperty ||
if (change.Property == MotionWidthProperty ||
change.Property == MotionHeightProperty ||
change.Property == MotionOpacityProperty ||
change.Property == MotionRenderTransformProperty)
{
@ -341,7 +373,9 @@ public class MotionActor : Animatable, IMotionActor
{
var target = GetAnimatableGhost();
if (target == MotionTarget)
{
foreach (var motionConfig in _motion.GetMotionConfigs())
{
if (motionConfig.Property == MotionHeightProperty)
{
target.SetValue(MotionHeightProperty, _originHeight);
@ -360,9 +394,10 @@ public class MotionActor : Animatable, IMotionActor
target.SetValue(MotionRenderTransformProperty, _originRenderTransform);
target.SetValue(Visual.RenderTransformOriginProperty, _originRenderTransformOrigin);
}
}
}
}
private class AnimationState
{
public ITransition? Transition { get; set; }

View File

@ -42,7 +42,9 @@ public class MoveDownInMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.StartValue = BuildTranslateTransform(0, -motionTarget.DesiredSize.Height);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -56,7 +58,6 @@ public class MoveDownInMotion : AbstractMotion
}
}
public class MoveDownOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -94,7 +95,9 @@ public class MoveDownOutMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.EndValue = BuildTranslateTransform(0, -motionTarget.DesiredSize.Height);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -108,7 +111,6 @@ public class MoveDownOutMotion : AbstractMotion
}
}
public class MoveLeftInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -145,7 +147,9 @@ public class MoveLeftInMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.StartValue = BuildTranslateTransform(-motionTarget.DesiredSize.Width, 0);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -159,7 +163,6 @@ public class MoveLeftInMotion : AbstractMotion
}
}
public class MoveLeftOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -197,7 +200,9 @@ public class MoveLeftOutMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.EndValue = BuildTranslateTransform(-motionTarget.DesiredSize.Width, 0);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -211,7 +216,6 @@ public class MoveLeftOutMotion : AbstractMotion
}
}
public class MoveRightInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -248,7 +252,9 @@ public class MoveRightInMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.StartValue = BuildTranslateTransform(motionTarget.DesiredSize.Width, 0);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -257,7 +263,6 @@ public class MoveRightInMotion : AbstractMotion
}
}
public class MoveRightOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -294,7 +299,9 @@ public class MoveRightOutMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.EndValue = BuildTranslateTransform(motionTarget.DesiredSize.Width, 0);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -303,7 +310,6 @@ public class MoveRightOutMotion : AbstractMotion
}
}
public class MoveUpInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -341,7 +347,9 @@ public class MoveUpInMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.StartValue = BuildTranslateTransform(0, motionTarget.DesiredSize.Height);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)
@ -350,7 +358,6 @@ public class MoveUpInMotion : AbstractMotion
}
}
public class MoveUpOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -388,7 +395,9 @@ public class MoveUpOutMotion : AbstractMotion
{
base.NotifyPreBuildTransition(config, motionTarget);
if (config.Property == MotionRenderTransformProperty)
{
config.EndValue = BuildTranslateTransform(0, motionTarget.DesiredSize.Height);
}
}
internal override Size CalculateSceneSize(Size motionTargetSize)

View File

@ -28,7 +28,7 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
}
/// <summary>
/// 初始化一个新的动画顶层窗口
/// 初始化一个新的动画顶层窗口
/// </summary>
/// <param name="parent"></param>
/// <param name="impl"></param>
@ -38,11 +38,16 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
{
ParentTopLevel = parent;
impl.SetWindowManagerAddShadowHint(false);
if (this is WindowBase window) window.SetTransparentForMouseEvents(true);
if (this is WindowBase window)
{
window.SetTransparentForMouseEvents(true);
}
if (PlatformImpl?.PopupPositioner is ManagedPopupPositioner managedPopupPositioner)
{
_managedPopupPositionerPopup =
ManagedPopupPositionerPopupInfo.GetValue(managedPopupPositioner) as IManagedPopupPositionerPopup;
}
_layout = new Canvas();
Content = _layout;
@ -50,7 +55,7 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
}
/// <summary>
/// Gets the platform-specific window implementation.
/// Gets the platform-specific window implementation.
/// </summary>
public new IPopupImpl? PlatformImpl => (IPopupImpl?)base.PlatformImpl;
@ -62,7 +67,7 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
}
/// <summary>
/// Gets the control that is hosting the popup root.
/// Gets the control that is hosting the popup root.
/// </summary>
Visual? IHostedVisualTreeRoot.Host
{
@ -74,7 +79,11 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
// if set. This helps to allow the focus manager to restore the focus to the outer
// scope when the popup is closed.
var parentVisual = Parent as Visual;
if (parentVisual?.GetVisualRoot() != null) return parentVisual;
if (parentVisual?.GetVisualRoot() != null)
{
return parentVisual;
}
return ParentTopLevel ?? parentVisual;
}
}
@ -90,9 +99,15 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
var maxAutoSize = PlatformImpl?.MaxAutoSizeHint ?? Size.Infinity;
var constraint = availableSize;
if (double.IsInfinity(constraint.Width)) constraint = constraint.WithWidth(maxAutoSize.Width);
if (double.IsInfinity(constraint.Width))
{
constraint = constraint.WithWidth(maxAutoSize.Width);
}
if (double.IsInfinity(constraint.Height)) constraint = constraint.WithHeight(maxAutoSize.Height);
if (double.IsInfinity(constraint.Height))
{
constraint = constraint.WithHeight(maxAutoSize.Height);
}
var measured = base.MeasureOverride(constraint);
var width = measured.Width;
@ -100,12 +115,18 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
var widthCache = Width;
var heightCache = Height;
if (!double.IsNaN(widthCache)) width = widthCache;
if (!double.IsNaN(widthCache))
{
width = widthCache;
}
width = Math.Min(width, MaxWidth);
width = Math.Max(width, MinWidth);
if (!double.IsNaN(heightCache)) height = heightCache;
if (!double.IsNaN(heightCache))
{
height = heightCache;
}
height = Math.Min(height, MaxHeight);
height = Math.Max(height, MinHeight);
@ -129,7 +150,11 @@ public class SceneLayer : WindowBase, IHostedVisualTreeRoot, IDisposable
{
base.OnOpened(e);
foreach (var child in _layout.Children)
{
if (child is INotifyCaptureGhostBitmap captureGhost)
{
captureGhost.NotifyCaptureGhostBitmap();
}
}
}
}

View File

@ -39,7 +39,6 @@ public class SlideUpInMotion : AbstractMotion
}
}
public class SlideUpOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -75,7 +74,6 @@ public class SlideUpOutMotion : AbstractMotion
}
}
public class SlideDownInMotion : AbstractMotion
{
public SlideDownInMotion()
@ -122,7 +120,6 @@ public class SlideDownInMotion : AbstractMotion
}
}
public class SlideDownOutMotion : AbstractMotion
{
public SlideDownOutMotion()
@ -169,7 +166,6 @@ public class SlideDownOutMotion : AbstractMotion
}
}
public class SlideLeftInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -205,7 +201,6 @@ public class SlideLeftInMotion : AbstractMotion
}
}
public class SlideLeftOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -241,7 +236,6 @@ public class SlideLeftOutMotion : AbstractMotion
}
}
public class SlideRightInMotion : AbstractMotion
{
public SlideRightInMotion()
@ -288,7 +282,6 @@ public class SlideRightInMotion : AbstractMotion
}
}
public class SlideRightOutMotion : AbstractMotion
{
public SlideRightOutMotion()

View File

@ -39,7 +39,6 @@ public class ZoomInMotion : AbstractMotion
}
}
public class ZoomOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -75,7 +74,6 @@ public class ZoomOutMotion : AbstractMotion
}
}
public class ZoomBigInMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -112,7 +110,6 @@ public class ZoomBigInMotion : AbstractMotion
}
}
public class ZoomBigOutMotion : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -148,7 +145,6 @@ public class ZoomBigOutMotion : AbstractMotion
}
}
public class ZoomUpInMotion : AbstractMotion
{
public ZoomUpInMotion()
@ -195,7 +191,6 @@ public class ZoomUpInMotion : AbstractMotion
}
}
public class ZoomUpOutMotion : AbstractMotion
{
public ZoomUpOutMotion()
@ -242,7 +237,6 @@ public class ZoomUpOutMotion : AbstractMotion
}
}
public class ZoomLeftInMotion : AbstractMotion
{
public ZoomLeftInMotion()
@ -289,7 +283,6 @@ public class ZoomLeftInMotion : AbstractMotion
}
}
public class ZoomLeftOutMotion : AbstractMotion
{
public ZoomLeftOutMotion()
@ -336,7 +329,6 @@ public class ZoomLeftOutMotion : AbstractMotion
}
}
public class ZoomRightInMotion : AbstractMotion
{
public ZoomRightInMotion()
@ -383,7 +375,6 @@ public class ZoomRightInMotion : AbstractMotion
}
}
public class ZoomRightOutMotion : AbstractMotion
{
public ZoomRightOutMotion()
@ -430,7 +421,6 @@ public class ZoomRightOutMotion : AbstractMotion
}
}
public class ZoomDownInMotion : AbstractMotion
{
public ZoomDownInMotion()
@ -477,7 +467,6 @@ public class ZoomDownInMotion : AbstractMotion
}
}
public class ZoomDownOutMotion : AbstractMotion
{
public ZoomDownOutMotion()

View File

@ -29,9 +29,14 @@ internal static class WindowExt
// 不是确定这样处理是否合适
if (flag)
{
currentStyles |= WS_EX_TRANSPARENT | WS_EX_LAYERED;
}
else
{
currentStyles &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
}
SetExtendedStyle(impl, currentStyles, false);
}
@ -42,9 +47,14 @@ internal static class WindowExt
// 不是确定这样处理是否合适
if (flag)
{
currentStyles |= WS_EX_TRANSPARENT | WS_EX_LAYERED;
}
else
{
currentStyles &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
}
SetExtendedStyle(impl, currentStyles, false);
}

View File

@ -3,29 +3,32 @@
namespace AtomUI.Reactive;
/// <summary>
/// Extension methods associated with the IDisposable interface.
/// Extension methods associated with the IDisposable interface.
/// </summary>
internal static class DisposableMixin
{
/// <summary>
/// Ensures the provided disposable is disposed with the specified <see cref="CompositeDisposable" />.
/// </summary>
/// <typeparam name="T">
/// The type of the disposable.
/// </typeparam>
/// <param name="item">
/// The disposable we are going to want to be disposed by the CompositeDisposable.
/// </param>
/// <param name="compositeDisposable">
/// The <see cref="CompositeDisposable" /> to which <paramref name="item" /> will be added.
/// </param>
/// <returns>
/// The disposable.
/// </returns>
public static T DisposeWith<T>(this T item, CompositeDisposable compositeDisposable)
/// <summary>
/// Ensures the provided disposable is disposed with the specified <see cref="CompositeDisposable" />.
/// </summary>
/// <typeparam name="T">
/// The type of the disposable.
/// </typeparam>
/// <param name="item">
/// The disposable we are going to want to be disposed by the CompositeDisposable.
/// </param>
/// <param name="compositeDisposable">
/// The <see cref="CompositeDisposable" /> to which <paramref name="item" /> will be added.
/// </param>
/// <returns>
/// The disposable.
/// </returns>
public static T DisposeWith<T>(this T item, CompositeDisposable compositeDisposable)
where T : IDisposable
{
if (compositeDisposable is null) throw new ArgumentNullException(nameof(compositeDisposable));
if (compositeDisposable is null)
{
throw new ArgumentNullException(nameof(compositeDisposable));
}
compositeDisposable.Add(item);
return item;

View File

@ -54,14 +54,22 @@ public static class ObjectExtension
}
public static T? GetPropertyOrThrow<T>(this object source, string name,
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
BindingFlags flags =
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
{
var obj = source.GetType().GetPropertyInfoOrThrow(name, flags).GetValue(source);
if (obj is T propertyOrThrow) return propertyOrThrow;
if (obj is T propertyOrThrow)
{
return propertyOrThrow;
}
if (obj == null)
{
if (typeof(T).IsValueType) throw new Exception(name + " is a value type but the value is null.");
if (typeof(T).IsValueType)
{
throw new Exception(name + " is a value type but the value is null.");
}
return default;
}
@ -83,11 +91,17 @@ public static class ObjectExtension
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
{
var obj = declareType.GetPropertyInfoOrThrow(name, flags).GetValue(source);
if (obj is T propertyOrThrow) return propertyOrThrow;
if (obj is T propertyOrThrow)
{
return propertyOrThrow;
}
if (obj == null)
{
if (typeof(T).IsValueType) throw new Exception(name + " is a value type but the value is null.");
if (typeof(T).IsValueType)
{
throw new Exception(name + " is a value type but the value is null.");
}
return default;
}
@ -110,7 +124,10 @@ public static class ObjectExtension
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic)
{
var property = declareType.GetProperty(name, flags);
if (property is null) return false;
if (property is null)
{
return false;
}
property.SetValue(source, value);
return true;
@ -165,15 +182,22 @@ public static class ObjectExtension
}
public static T? GetFieldOrThrow<T>(this object source, string name,
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
BindingFlags flags =
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
{
var obj = source.GetType().GetFieldInfoOrThrow(name, flags).GetValue(source);
if (obj is T fieldOrThrow) return fieldOrThrow;
if (obj is T fieldOrThrow)
{
return fieldOrThrow;
}
if (obj == null)
{
if (typeof(T).IsValueType) throw new Exception(name + " is a value type but the value is null.");
if (typeof(T).IsValueType)
{
throw new Exception(name + " is a value type but the value is null.");
}
return default;
}
@ -195,10 +219,17 @@ public static class ObjectExtension
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
{
var obj = declareType.GetFieldInfoOrThrow(name, flags).GetValue(source);
if (obj is T fieldOrThrow) return fieldOrThrow;
if (obj is T fieldOrThrow)
{
return fieldOrThrow;
}
if (obj == null)
{
if (typeof(T).IsValueType) throw new Exception(name + " is a value type but the value is null.");
if (typeof(T).IsValueType)
{
throw new Exception(name + " is a value type but the value is null.");
}
return default;
}
@ -221,7 +252,10 @@ public static class ObjectExtension
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
{
var field = declareType.GetField(name, flags);
if (field is null) return false;
if (field is null)
{
return false;
}
field.SetValue(source, value);
return true;

View File

@ -45,29 +45,39 @@ public static class TypeExtension
PropertyInfo? info;
if (!type.TryGetPropertyInfo(name, out info, flags))
{
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
}
return info;
}
public static FieldInfo GetFieldInfoOrThrow(this Type type, string name,
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
BindingFlags flags =
BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.FlattenHierarchy)
{
FieldInfo? info;
if (!type.TryGetFieldInfo(name, out info, flags))
{
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
}
return info;
}
public static MethodInfo GetMethodInfoOrThrow(this Type type, string name,
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.FlattenHierarchy)
BindingFlags flags =
BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.FlattenHierarchy)
{
MethodInfo? info;
if (!type.TryGetMethodInfo(name, out info, flags))
{
throw new NotSupportedException($"Can not find the '{name}' from type '{type}'. We can not reflect it.");
}
return info;
}

View File

@ -3,7 +3,7 @@
namespace AtomUI.Utils;
/// <summary>
/// Provides extension methods for enums.
/// Provides extension methods for enums.
/// </summary>
internal static class EnumExtensions
{

View File

@ -16,23 +16,27 @@ public static class MathUtils
}
/// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
public static bool AreClose(double value1, double value2)
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
if (value1 == value2)
{
return true;
}
var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DoubleEpsilon;
var delta = value1 - value2;
return -eps < delta && eps > delta;
}
/// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
@ -40,30 +44,38 @@ public static class MathUtils
public static bool AreClose(double value1, double value2, double eps)
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
if (value1 == value2)
{
return true;
}
var delta = value1 - value2;
return -eps < delta && eps > delta;
}
/// <summary>
/// AreClose - Returns whether or not two floats are "close". That is, whether or
/// not they are within epsilon of each other.
/// AreClose - Returns whether or not two floats are "close". That is, whether or
/// not they are within epsilon of each other.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
public static bool AreClose(float value1, float value2)
{
//in case they are Infinities (then epsilon check does not work)
if (value1 == value2) return true;
if (value1 == value2)
{
return true;
}
var eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0f) * FloatEpsilon;
var delta = value1 - value2;
return -eps < delta && eps > delta;
}
/// <summary>
/// LessThan - Returns whether or not the first double is less than the second double.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number.
/// LessThan - Returns whether or not the first double is less than the second double.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
@ -73,9 +85,9 @@ public static class MathUtils
}
/// <summary>
/// LessThan - Returns whether or not the first float is less than the second float.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number.
/// LessThan - Returns whether or not the first float is less than the second float.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first single float to compare. </param>
/// <param name="value2"> The second single float to compare. </param>
@ -85,9 +97,9 @@ public static class MathUtils
}
/// <summary>
/// GreaterThan - Returns whether or not the first double is greater than the second double.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number.
/// GreaterThan - Returns whether or not the first double is greater than the second double.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
@ -97,9 +109,9 @@ public static class MathUtils
}
/// <summary>
/// GreaterThan - Returns whether or not the first float is greater than the second float.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number.
/// GreaterThan - Returns whether or not the first float is greater than the second float.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
@ -109,9 +121,9 @@ public static class MathUtils
}
/// <summary>
/// LessThanOrClose - Returns whether or not the first double is less than or close to
/// the second double. That is, whether or not the first is strictly less than or within
/// epsilon of the other number.
/// LessThanOrClose - Returns whether or not the first double is less than or close to
/// the second double. That is, whether or not the first is strictly less than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
@ -121,9 +133,9 @@ public static class MathUtils
}
/// <summary>
/// LessThanOrClose - Returns whether or not the first float is less than or close to
/// the second float. That is, whether or not the first is strictly less than or within
/// epsilon of the other number.
/// LessThanOrClose - Returns whether or not the first float is less than or close to
/// the second float. That is, whether or not the first is strictly less than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
@ -133,9 +145,9 @@ public static class MathUtils
}
/// <summary>
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
/// the second double. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number.
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
/// the second double. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first double to compare. </param>
/// <param name="value2"> The second double to compare. </param>
@ -145,9 +157,9 @@ public static class MathUtils
}
/// <summary>
/// GreaterThanOrClose - Returns whether or not the first float is greater than or close to
/// the second float. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number.
/// GreaterThanOrClose - Returns whether or not the first float is greater than or close to
/// the second float. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number.
/// </summary>
/// <param name="value1"> The first float to compare. </param>
/// <param name="value2"> The second float to compare. </param>
@ -157,8 +169,8 @@ public static class MathUtils
}
/// <summary>
/// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
/// but this is faster.
/// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
/// but this is faster.
/// </summary>
/// <param name="value"> The double to compare to 1. </param>
public static bool IsOne(double value)
@ -167,8 +179,8 @@ public static class MathUtils
}
/// <summary>
/// IsOne - Returns whether or not the float is "close" to 1. Same as AreClose(float, 1),
/// but this is faster.
/// IsOne - Returns whether or not the float is "close" to 1. Same as AreClose(float, 1),
/// but this is faster.
/// </summary>
/// <param name="value"> The float to compare to 1. </param>
public static bool IsOne(float value)
@ -177,8 +189,8 @@ public static class MathUtils
}
/// <summary>
/// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
/// but this is faster.
/// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
/// but this is faster.
/// </summary>
/// <param name="value"> The double to compare to 0. </param>
public static bool IsZero(double value)
@ -187,8 +199,8 @@ public static class MathUtils
}
/// <summary>
/// IsZero - Returns whether or not the float is "close" to 0. Same as AreClose(float, 0),
/// but this is faster.
/// IsZero - Returns whether or not the float is "close" to 0. Same as AreClose(float, 0),
/// but this is faster.
/// </summary>
/// <param name="value"> The float to compare to 0. </param>
public static bool IsZero(float value)
@ -197,7 +209,7 @@ public static class MathUtils
}
/// <summary>
/// Converts an angle in degrees to radians.
/// Converts an angle in degrees to radians.
/// </summary>
/// <param name="angle">The angle in degrees.</param>
/// <returns>The angle in radians.</returns>
@ -207,7 +219,7 @@ public static class MathUtils
}
/// <summary>
/// Converts an angle in gradians to radians.
/// Converts an angle in gradians to radians.
/// </summary>
/// <param name="angle">The angle in gradians.</param>
/// <returns>The angle in radians.</returns>
@ -217,7 +229,7 @@ public static class MathUtils
}
/// <summary>
/// Converts an angle in turns to radians.
/// Converts an angle in turns to radians.
/// </summary>
/// <param name="angle">The angle in turns.</param>
/// <returns>The angle in radians.</returns>
@ -227,7 +239,7 @@ public static class MathUtils
}
/// <summary>
/// Calculates the point of an angle on an ellipse.
/// Calculates the point of an angle on an ellipse.
/// </summary>
/// <param name="centre">The centre point of the ellipse.</param>
/// <param name="radiusX">The x radius of the ellipse.</param>

View File

@ -17,7 +17,6 @@ public enum AddOnDecoratedVariant
Borderless
}
public enum AddOnDecoratedStatus
{
Default,
@ -25,7 +24,6 @@ public enum AddOnDecoratedStatus
Error
}
[TemplatePart(AddOnDecoratedBoxTheme.LeftAddOnPart, typeof(ContentPresenter))]
[TemplatePart(AddOnDecoratedBoxTheme.RightAddOnPart, typeof(ContentPresenter))]
[TemplatePart(AddOnDecoratedBoxTheme.InnerBoxContentPart, typeof(ContentPresenter), IsRequired = true)]
@ -48,17 +46,29 @@ public class AddOnDecoratedBox : ContentControl
base.OnPropertyChanged(change);
if (VisualRoot is not null)
{
if (change.Property == LeftAddOnProperty || change.Property == RightAddOnProperty)
{
SetupInnerBoxCornerRadius();
}
}
if (change.Property == CornerRadiusProperty || change.Property == BorderThicknessProperty)
{
SetupAddOnBorderInfo();
}
if (change.Property == StatusProperty) UpdatePseudoClasses();
if (change.Property == StatusProperty)
{
UpdatePseudoClasses();
}
if (change.Property == LeftAddOnProperty || change.Property == RightAddOnProperty)
{
if (change.NewValue is PathIcon icon) SetupIconTypeAddOnSize(icon);
if (change.NewValue is PathIcon icon)
{
SetupIconTypeAddOnSize(icon);
}
}
else if (change.Property == ContentProperty)
{
@ -71,9 +81,15 @@ public class AddOnDecoratedBox : ContentControl
if (change.Property == SizeTypeProperty)
{
if (LeftAddOn is PathIcon leftIconAddOn) SetupIconTypeAddOnSize(leftIconAddOn);
if (LeftAddOn is PathIcon leftIconAddOn)
{
SetupIconTypeAddOnSize(leftIconAddOn);
}
if (RightAddOn is PathIcon rightIconAddOn) SetupIconTypeAddOnSize(rightIconAddOn);
if (RightAddOn is PathIcon rightIconAddOn)
{
SetupIconTypeAddOnSize(rightIconAddOn);
}
}
}
@ -173,12 +189,10 @@ public class AddOnDecoratedBox : ContentControl
protected virtual void UpdatePseudoClasses()
{
PseudoClasses.Set(ErrorPC, Status == AddOnDecoratedStatus.Error);
PseudoClasses.Set(ErrorPC, Status == AddOnDecoratedStatus.Error);
PseudoClasses.Set(WarningPC, Status == AddOnDecoratedStatus.Warning);
}
#region
public static readonly StyledProperty<object?> LeftAddOnProperty =
@ -229,8 +243,6 @@ public class AddOnDecoratedBox : ContentControl
#endregion
#region
internal static readonly DirectProperty<AddOnDecoratedBox, CornerRadius> InnerBoxCornerRadiusProperty =

View File

@ -15,97 +15,97 @@ internal class AddOnDecoratedBoxToken : AbstractControlDesignToken
}
/// <summary>
/// 输入框内边距
/// 输入框内边距
/// </summary>
public Thickness Padding { get; set; }
/// <summary>
/// 小号输入框内边距
/// 小号输入框内边距
/// </summary>
public Thickness PaddingSM { get; set; }
/// <summary>
/// 大号输入框内边距
/// 大号输入框内边距
/// </summary>
public Thickness PaddingLG { get; set; }
/// <summary>
/// 前/后置标签背景色
/// 前/后置标签背景色
/// </summary>
public Color AddonBg { get; set; }
/// <summary>
/// 悬浮态边框色
/// 悬浮态边框色
/// </summary>
public Color HoverBorderColor { get; set; }
/// <summary>
/// 激活态边框色
/// 激活态边框色
/// </summary>
public Color ActiveBorderColor { get; set; }
/// <summary>
/// 激活态阴影
/// 激活态阴影
/// </summary>
public BoxShadow ActiveShadow { get; set; }
/// <summary>
/// 错误状态时激活态阴影
/// 错误状态时激活态阴影
/// </summary>
public BoxShadow ErrorActiveShadow { get; set; }
/// <summary>
/// 警告状态时激活态阴影
/// 警告状态时激活态阴影
/// </summary>
public BoxShadow WarningActiveShadow { get; set; }
/// <summary>
/// hover 状态时背景颜色
/// hover 状态时背景颜色
/// </summary>
public Color HoverBg { get; set; }
/// <summary>
/// 激活状态时背景颜色
/// 激活状态时背景颜色
/// </summary>
public Color ActiveBg { get; set; }
/// <summary>
/// 字体大小
/// 字体大小
/// </summary>
public double FontSize { get; set; }
/// <summary>
/// 大号字体大小
/// 大号字体大小
/// </summary>
public double FontSizeLG { get; set; }
/// <summary>
/// 小号字体大小
/// 小号字体大小
/// </summary>
public double FontSizeSM { get; set; }
/// <summary>
/// AddOn 内边距
/// AddOn 内边距
/// </summary>
public Thickness AddOnPadding { get; set; }
/// <summary>
/// AddOn 小号内边距
/// AddOn 小号内边距
/// </summary>
public Thickness AddOnPaddingSM { get; set; }
/// <summary>
/// AddOn 大号内边距
/// AddOn 大号内边距
/// </summary>
public Thickness AddOnPaddingLG { get; set; }
/// <summary>
/// 左边内部小组件的边距
/// 左边内部小组件的边距
/// </summary>
public Thickness LeftInnerAddOnMargin { get; set; }
/// <summary>
/// 右边内部小组件的边距
/// 右边内部小组件的边距
/// </summary>
public Thickness RightInnerAddOnMargin { get; set; }
@ -117,9 +117,9 @@ internal class AddOnDecoratedBoxToken : AbstractControlDesignToken
var lineHeight = _globalToken.FontToken.LineHeight;
var lineHeightLG = _globalToken.FontToken.LineHeightLG;
var lineWidth = _globalToken.SeedToken.LineWidth;
Padding = new Thickness(_globalToken.PaddingSM - lineWidth,
Padding = new Thickness(_globalToken.PaddingSM - lineWidth,
Math.Round((_globalToken.SeedToken.ControlHeight - fontSize * lineHeight) / 2 * 10) / 10 - lineWidth);
PaddingSM = new Thickness(_globalToken.ControlPaddingSM - lineWidth,
PaddingSM = new Thickness(_globalToken.ControlPaddingSM - lineWidth,
Math.Round((_globalToken.HeightToken.ControlHeightSM - fontSize * lineHeight) / 2 * 10) / 10 - lineWidth);
PaddingLG = new Thickness(_globalToken.ControlPadding - lineWidth,
Math.Ceiling((_globalToken.HeightToken.ControlHeightLG - fontSizeLG * lineHeightLG) / 2 * 10) / 10 -

View File

@ -33,9 +33,15 @@ public class AddOnDecoratedInnerBox : ContentControl
if (change.Property == LeftAddOnContentProperty || change.Property == RightAddOnContentProperty)
{
if (change.OldValue is Control oldControl) UIStructureUtils.SetTemplateParent(oldControl, null);
if (change.OldValue is Control oldControl)
{
UIStructureUtils.SetTemplateParent(oldControl, null);
}
if (change.NewValue is Control newControl) UIStructureUtils.SetTemplateParent(newControl, this);
if (change.NewValue is Control newControl)
{
UIStructureUtils.SetTemplateParent(newControl, this);
}
}
}
@ -47,11 +53,20 @@ public class AddOnDecoratedInnerBox : ContentControl
_rightAddOnLayout = e.NameScope.Find<StackPanel>(AddOnDecoratedInnerBoxTheme.RightAddOnLayoutPart);
_clearButton = e.NameScope.Find<IconButton>(AddOnDecoratedInnerBoxTheme.ClearButtonPart);
if (_leftAddOnLayout is not null) _leftAddOnLayout.SizeChanged += HandleLayoutSizeChanged;
if (_rightAddOnLayout is not null) _rightAddOnLayout.SizeChanged += HandleLayoutSizeChanged;
if (_leftAddOnLayout is not null)
{
_leftAddOnLayout.SizeChanged += HandleLayoutSizeChanged;
}
if (_rightAddOnLayout is not null)
{
_rightAddOnLayout.SizeChanged += HandleLayoutSizeChanged;
}
if (_clearButton is not null)
{
_clearButton.Click += (sender, args) => { NotifyClearButtonClicked(); };
}
SetupContentPresenterMargin();
BuildEffectiveInnerBoxPadding();
@ -67,17 +82,24 @@ public class AddOnDecoratedInnerBox : ContentControl
var marginLeft = 0d;
var marginRight = 0d;
if (_leftAddOnLayout is not null)
{
if (_leftAddOnLayout.DesiredSize.Width > 0 && _leftAddOnLayout.DesiredSize.Height > 0)
{
marginLeft = _marginXSToken;
}
}
if (_rightAddOnLayout is not null)
{
if (_rightAddOnLayout.DesiredSize.Width > 0 && _rightAddOnLayout.DesiredSize.Height > 0)
{
marginRight = _marginXSToken;
}
}
ContentPresenterMargin = new Thickness(marginLeft, 0, marginRight, 0);
}
#region
public static readonly StyledProperty<SizeType> SizeTypeProperty =
@ -136,8 +158,6 @@ public class AddOnDecoratedInnerBox : ContentControl
#endregion
#region
internal static readonly StyledProperty<Thickness> InnerBoxPaddingProperty =

View File

@ -291,7 +291,8 @@ internal class AddOnDecoratedInnerBoxTheme : BaseControlTheme
{
var outlineStyle =
new Style(selector => selector.Nesting()
.PropertyEquals(AddOnDecoratedBox.StyleVariantProperty, AddOnDecoratedVariant.Outline));
.PropertyEquals(AddOnDecoratedBox.StyleVariantProperty,
AddOnDecoratedVariant.Outline));
{
{
@ -393,7 +394,7 @@ internal class AddOnDecoratedInnerBoxTheme : BaseControlTheme
var filledStyle =
new Style(selector =>
selector.Nesting()
.PropertyEquals(AddOnDecoratedBox.StyleVariantProperty, AddOnDecoratedVariant.Filled));
.PropertyEquals(AddOnDecoratedBox.StyleVariantProperty, AddOnDecoratedVariant.Filled));
{
{

View File

@ -16,7 +16,6 @@ public enum AlertType
Error
}
public class Alert : TemplatedControl, IControlCustomStyle
{
public static readonly StyledProperty<AlertType> TypeProperty =
@ -125,8 +124,6 @@ public class Alert : TemplatedControl, IControlCustomStyle
_customStyle.HandleTemplateApplied(e.NameScope);
}
#region IControlCustomStyle
void IControlCustomStyle.HandleTemplateApplied(INameScope scope)
@ -140,8 +137,12 @@ public class Alert : TemplatedControl, IControlCustomStyle
void IControlCustomStyle.HandlePropertyChangedForStyle(AvaloniaPropertyChangedEventArgs e)
{
if (VisualRoot is not null)
{
if (e.Property == IsClosableProperty)
{
SetupCloseButton();
}
}
}
private void SetupCloseButton()

View File

@ -379,7 +379,10 @@ internal class AlertTheme : BaseControlTheme
GlobalTokenResourceKey.MarginXS, BindingPriority.Template,
o =>
{
if (o is double value) return new Thickness(0, value, 0, 0);
if (o is double value)
{
return new Thickness(0, value, 0, 0);
}
return o;
});

View File

@ -14,47 +14,47 @@ internal class AlertToken : AbstractControlDesignToken
}
/// <summary>
/// 默认内间距
/// 默认内间距
/// </summary>
public Thickness DefaultPadding { get; set; }
/// <summary>
/// 带有描述的内间距
/// 带有描述的内间距
/// </summary>
public Thickness WithDescriptionPadding { get; set; }
/// <summary>
/// 带有描述的 Message 外间距
/// 带有描述的 Message 外间距
/// </summary>
public Thickness MessageWithDescriptionMargin { get; set; }
/// <summary>
/// 图标默认外间距
/// 图标默认外间距
/// </summary>
public Thickness IconDefaultMargin { get; set; }
/// <summary>
/// 图标带描述信息外间距
/// 图标带描述信息外间距
/// </summary>
public Thickness IconWithDescriptionMargin { get; set; }
/// <summary>
/// 没有描述时的图标尺寸
/// 没有描述时的图标尺寸
/// </summary>
public double IconSize { get; set; }
/// <summary>
/// 带有描述时的图标尺寸
/// 带有描述时的图标尺寸
/// </summary>
public double WithDescriptionIconSize { get; set; }
/// <summary>
/// 关闭按钮的大小
/// 关闭按钮的大小
/// </summary>
public double CloseIconSize { get; set; }
/// <summary>
/// 额外元素的外间距
/// 额外元素的外间距
/// </summary>
public Thickness ExtraElementMargin { get; set; }

View File

@ -11,90 +11,91 @@ namespace AtomUI.Controls;
public enum ArrowPosition
{
/// <summary>
/// Preferred location is below the target element.
/// </summary>
Bottom,
/// <summary>
/// Preferred location is below the target element.
/// </summary>
Bottom,
/// <summary>
/// Preferred location is to the right of the target element.
/// </summary>
Right,
/// <summary>
/// Preferred location is to the right of the target element.
/// </summary>
Right,
/// <summary>
/// Preferred location is to the left of the target element.
/// </summary>
Left,
/// <summary>
/// Preferred location is to the left of the target element.
/// </summary>
Left,
/// <summary>
/// Preferred location is above the target element.
/// </summary>
Top,
/// <summary>
/// Preferred location is above the target element.
/// </summary>
Top,
/// <summary>
/// Preferred location is above the target element, with the left edge of the popup
/// aligned with the left edge of the target element.
/// </summary>
TopEdgeAlignedLeft,
/// <summary>
/// Preferred location is above the target element, with the left edge of the popup
/// aligned with the left edge of the target element.
/// </summary>
TopEdgeAlignedLeft,
/// <summary>
/// Preferred location is above the target element, with the right edge of popup aligned with right edge of the target
/// element.
/// </summary>
TopEdgeAlignedRight,
/// <summary>
/// Preferred location is above the target element, with the right edge of popup aligned with right edge of the target
/// element.
/// </summary>
TopEdgeAlignedRight,
/// <summary>
/// Preferred location is below the target element, with the left edge of popup aligned with left edge of the target
/// element.
/// </summary>
BottomEdgeAlignedLeft,
/// <summary>
/// Preferred location is below the target element, with the left edge of popup aligned with left edge of the target
/// element.
/// </summary>
BottomEdgeAlignedLeft,
/// <summary>
/// Preferred location is below the target element, with the right edge of popup aligned with right edge of the target
/// element.
/// </summary>
BottomEdgeAlignedRight,
/// <summary>
/// Preferred location is below the target element, with the right edge of popup aligned with right edge of the target
/// element.
/// </summary>
BottomEdgeAlignedRight,
/// <summary>
/// Preferred location is to the left of the target element, with the top edge of popup aligned with top edge of the
/// target element.
/// </summary>
LeftEdgeAlignedTop,
/// <summary>
/// Preferred location is to the left of the target element, with the top edge of popup aligned with top edge of the
/// target element.
/// </summary>
LeftEdgeAlignedTop,
/// <summary>
/// Preferred location is to the left of the target element, with the bottom edge of popup aligned with bottom edge of
/// the target element.
/// </summary>
LeftEdgeAlignedBottom,
/// <summary>
/// Preferred location is to the left of the target element, with the bottom edge of popup aligned with bottom edge of
/// the target element.
/// </summary>
LeftEdgeAlignedBottom,
/// <summary>
/// Preferred location is to the right of the target element, with the top edge of popup aligned with top edge of the
/// target element.
/// </summary>
RightEdgeAlignedTop,
/// <summary>
/// Preferred location is to the right of the target element, with the top edge of popup aligned with top edge of the
/// target element.
/// </summary>
RightEdgeAlignedTop,
/// <summary>
/// Preferred location is to the right of the target element, with the bottom edge of popup aligned with bottom edge of
/// the target element.
/// </summary>
RightEdgeAlignedBottom
/// <summary>
/// Preferred location is to the right of the target element, with the bottom edge of popup aligned with bottom edge of
/// the target element.
/// </summary>
RightEdgeAlignedBottom
}
public class ArrowDecoratedBox : ContentControl,
IShadowMaskInfoProvider,
IControlCustomStyle
IShadowMaskInfoProvider,
IControlCustomStyle
{
public static readonly StyledProperty<bool> IsShowArrowProperty =
AvaloniaProperty.Register<ArrowDecoratedBox, bool>(nameof(IsShowArrow), true);
public static readonly StyledProperty<ArrowPosition> ArrowPositionProperty =
AvaloniaProperty.Register<ArrowDecoratedBox, ArrowPosition>(
nameof(ArrowPosition), ArrowPosition.Bottom);
nameof(ArrowPosition));
internal static readonly StyledProperty<double> ArrowSizeProperty
= AvaloniaProperty.Register<ArrowDecoratedBox, double>(nameof(ArrowSize));
private readonly IControlCustomStyle _customStyle;
private Geometry? _arrowGeometry;
private Rect _arrowRect;
@ -102,8 +103,6 @@ public class ArrowDecoratedBox : ContentControl,
// 相对坐标
private (double, double) _arrowVertexPoint;
private Rect _contentRect;
private readonly IControlCustomStyle _customStyle;
private bool _needGenerateArrowVertexPoint = true;
static ArrowDecoratedBox()
@ -119,7 +118,7 @@ public class ArrowDecoratedBox : ContentControl,
internal (double, double) ArrowVertexPoint => GetArrowVertexPoint();
/// <summary>
/// 是否显示指示箭头
/// 是否显示指示箭头
/// </summary>
public bool IsShowArrow
{
@ -128,7 +127,7 @@ public class ArrowDecoratedBox : ContentControl,
}
/// <summary>
/// 箭头渲染的位置
/// 箭头渲染的位置
/// </summary>
public ArrowPosition ArrowPosition
{
@ -137,7 +136,7 @@ public class ArrowDecoratedBox : ContentControl,
}
/// <summary>
/// 箭头的大小
/// 箭头的大小
/// </summary>
internal double ArrowSize
{
@ -147,7 +146,10 @@ public class ArrowDecoratedBox : ContentControl,
void IControlCustomStyle.HandleTemplateApplied(INameScope scope)
{
if (IsShowArrow) BuildGeometry(true);
if (IsShowArrow)
{
BuildGeometry(true);
}
}
public CornerRadius GetMaskCornerRadius()
@ -164,20 +166,20 @@ public class ArrowDecoratedBox : ContentControl,
{
return arrowPosition switch
{
ArrowPosition.Left => Direction.Left,
ArrowPosition.Left => Direction.Left,
ArrowPosition.LeftEdgeAlignedBottom => Direction.Left,
ArrowPosition.LeftEdgeAlignedTop => Direction.Left,
ArrowPosition.LeftEdgeAlignedTop => Direction.Left,
ArrowPosition.Top => Direction.Top,
ArrowPosition.TopEdgeAlignedLeft => Direction.Top,
ArrowPosition.Top => Direction.Top,
ArrowPosition.TopEdgeAlignedLeft => Direction.Top,
ArrowPosition.TopEdgeAlignedRight => Direction.Top,
ArrowPosition.Right => Direction.Right,
ArrowPosition.Right => Direction.Right,
ArrowPosition.RightEdgeAlignedBottom => Direction.Right,
ArrowPosition.RightEdgeAlignedTop => Direction.Right,
ArrowPosition.RightEdgeAlignedTop => Direction.Right,
ArrowPosition.Bottom => Direction.Bottom,
ArrowPosition.BottomEdgeAlignedLeft => Direction.Bottom,
ArrowPosition.Bottom => Direction.Bottom,
ArrowPosition.BottomEdgeAlignedLeft => Direction.Bottom,
ArrowPosition.BottomEdgeAlignedRight => Direction.Bottom,
_ => throw new ArgumentOutOfRangeException(nameof(arrowPosition), arrowPosition,
"Invalid value for ArrowPosition")
@ -196,8 +198,6 @@ public class ArrowDecoratedBox : ContentControl,
_customStyle.HandleTemplateApplied(e.NameScope);
}
#region IControlCustomStyle
private (double, double) GetArrowVertexPoint()
@ -214,15 +214,17 @@ public class ArrowDecoratedBox : ContentControl,
void IControlCustomStyle.HandlePropertyChangedForStyle(AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == IsShowArrowProperty ||
if (e.Property == IsShowArrowProperty ||
e.Property == ArrowPositionProperty ||
e.Property == ArrowSizeProperty ||
e.Property == ArrowSizeProperty ||
e.Property == VisualParentProperty)
{
if (e.Property == IsShowArrowProperty && VisualRoot is null)
// 当开启的时候,但是还没有加入的渲染树,这个时候我们取不到 Token 需要在取值的时候重新生成一下
{
_needGenerateArrowVertexPoint = true;
}
if (VisualRoot is not null)
{
@ -234,7 +236,10 @@ public class ArrowDecoratedBox : ContentControl,
private void BuildGeometry(bool force = false)
{
if (_arrowGeometry is null || force) _arrowGeometry = CommonShapeBuilder.BuildArrow(ArrowSize, 1.5);
if (_arrowGeometry is null || force)
{
_arrowGeometry = CommonShapeBuilder.BuildArrow(ArrowSize, 1.5);
}
}
public sealed override void Render(DrawingContext context)
@ -283,9 +288,13 @@ public class ArrowDecoratedBox : ContentControl,
var realArrowSize = Math.Min(_arrowGeometry!.Bounds.Size.Height, _arrowGeometry!.Bounds.Size.Width);
var direction = GetDirection(ArrowPosition);
if (direction == Direction.Left || direction == Direction.Right)
{
targetWidth += realArrowSize;
}
else
{
targetHeight += realArrowSize;
}
}
var targetSize = new Size(targetWidth, targetHeight);
@ -301,7 +310,10 @@ public class ArrowDecoratedBox : ContentControl,
for (var i = 0; i < visualCount; ++i)
{
var child = visualChildren[i];
if (child is Layoutable layoutable) layoutable.Arrange(_contentRect);
if (child is Layoutable layoutable)
{
layoutable.Arrange(_contentRect);
}
}
return finalSize;
@ -318,18 +330,30 @@ public class ArrowDecoratedBox : ContentControl,
var arrowSize = Math.Min(_arrowGeometry!.Bounds.Size.Height, _arrowGeometry!.Bounds.Size.Width) + 0.5;
var direction = GetDirection(ArrowPosition);
if (direction == Direction.Left || direction == Direction.Right)
{
targetWidth -= arrowSize;
}
else
{
targetHeight -= arrowSize;
}
if (direction == Direction.Right)
{
offsetX = 0.5;
}
else if (direction == Direction.Bottom)
{
offsetY = 0.5;
}
else if (direction == Direction.Top)
{
offsetY = arrowSize - 0.5;
}
else
{
offsetX = arrowSize - 0.5;
}
}
return new Rect(offsetX, offsetY, targetWidth, targetHeight);
@ -348,7 +372,7 @@ public class ArrowDecoratedBox : ContentControl,
var minValue = Math.Min(size.Width, size.Height);
var maxValue = Math.Max(size.Width, size.Height);
if (position == ArrowPosition.Left ||
if (position == ArrowPosition.Left ||
position == ArrowPosition.LeftEdgeAlignedTop ||
position == ArrowPosition.LeftEdgeAlignedBottom)
{
@ -361,33 +385,47 @@ public class ArrowDecoratedBox : ContentControl,
else if (position == ArrowPosition.LeftEdgeAlignedTop)
{
if (maxValue * 2 > finalSize.Height / 2)
{
offsetY = minValue;
}
else
{
offsetY = maxValue;
}
}
else
{
if (maxValue * 2 > finalSize.Height / 2)
{
offsetY = finalSize.Height - minValue - maxValue;
}
else
{
offsetY = finalSize.Height - maxValue * 2;
}
}
}
else if (position == ArrowPosition.Top ||
else if (position == ArrowPosition.Top ||
position == ArrowPosition.TopEdgeAlignedLeft ||
position == ArrowPosition.TopEdgeAlignedRight)
{
if (position == ArrowPosition.TopEdgeAlignedLeft)
{
offsetX = maxValue;
}
else if (position == ArrowPosition.Top)
{
offsetX = (finalSize.Width - maxValue) / 2;
}
else
{
offsetX = finalSize.Width - maxValue * 2;
}
targetWidth = maxValue;
targetHeight = minValue;
}
else if (position == ArrowPosition.Right ||
else if (position == ArrowPosition.Right ||
position == ArrowPosition.RightEdgeAlignedTop ||
position == ArrowPosition.RightEdgeAlignedBottom)
{
@ -399,16 +437,24 @@ public class ArrowDecoratedBox : ContentControl,
else if (position == ArrowPosition.RightEdgeAlignedTop)
{
if (maxValue * 2 > finalSize.Height / 2)
{
offsetY = minValue;
}
else
{
offsetY = maxValue;
}
}
else
{
if (maxValue * 2 > finalSize.Height / 2)
{
offsetY = finalSize.Height - minValue - maxValue;
}
else
{
offsetY = finalSize.Height - maxValue * 2;
}
}
targetWidth = minValue;
@ -420,11 +466,17 @@ public class ArrowDecoratedBox : ContentControl,
targetWidth = maxValue;
targetHeight = minValue;
if (position == ArrowPosition.BottomEdgeAlignedLeft)
{
offsetX = maxValue;
}
else if (position == ArrowPosition.Bottom)
{
offsetX = (finalSize.Width - maxValue) / 2;
}
else
{
offsetX = finalSize.Width - maxValue * 2;
}
}
}
@ -434,9 +486,13 @@ public class ArrowDecoratedBox : ContentControl,
// 计算中点
var direction = GetDirection(position);
if (direction == Direction.Left || direction == Direction.Right)
{
_arrowVertexPoint = (center.Y, finalSize.Height - center.Y);
}
else if (direction == Direction.Top || direction == Direction.Bottom)
{
_arrowVertexPoint = (center.X, finalSize.Width - center.X);
}
return targetRect;
}

View File

@ -14,12 +14,12 @@ public class ArrowDecoratedBoxToken : AbstractControlDesignToken
}
/// <summary>
/// 箭头三角形大小
/// 箭头三角形大小
/// </summary>
public double ArrowSize { get; set; }
/// <summary>
/// 默认的内边距
/// 默认的内边距
/// </summary>
public Thickness Padding { get; set; }

View File

@ -1,50 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=addondecoratedbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=alert/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=arrowdecoratedbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=badge/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=buttons/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=buttonspinner/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=checkbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=collapse/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=combobox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datepicker/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=drawer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=emptyindicator/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=expander/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=flyouts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=groupbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=input/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=listbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=loading/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=localization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=marqueelabel/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=menu/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=message/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=notifications/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=numericupdown/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=optionbuttonbox/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pathicon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=popup/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=popupconfirm/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=popupconfirm_005Clocalization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=primitives/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=primitives_005Catomlayer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=progressbar/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=radiobutton/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=segmented/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=separator/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=slider/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=switch/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tabcontrol/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tabcontrol_005Ctabstrip/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tag/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=timepicker/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=timepicker_005Clocalization/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=tooltip/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=treeview/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utils/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utils_005Cmotion/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=watermark/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=watermark_005Cglyphs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=window/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -15,37 +15,37 @@ internal class BadgeToken : AbstractControlDesignToken
}
/// <summary>
/// 徽标高度
/// 徽标高度
/// </summary>
public double IndicatorHeight { get; set; }
/// <summary>
/// 小号徽标高度
/// 小号徽标高度
/// </summary>
public double IndicatorHeightSM { get; set; }
/// <summary>
/// 点状徽标尺寸
/// 点状徽标尺寸
/// </summary>
public double DotSize { get; set; }
/// <summary>
/// 徽标文本尺寸
/// 徽标文本尺寸
/// </summary>
public double TextFontSize { get; set; }
/// <summary>
/// 小号徽标文本尺寸
/// 小号徽标文本尺寸
/// </summary>
public double TextFontSizeSM { get; set; }
/// <summary>
/// 徽标文本粗细
/// 徽标文本粗细
/// </summary>
public FontWeight TextFontWeight { get; set; }
/// <summary>
/// 状态徽标尺寸
/// 状态徽标尺寸
/// </summary>
public double StatusSize { get; set; }
@ -78,8 +78,6 @@ internal class BadgeToken : AbstractControlDesignToken
BadgeRibbonTextPadding = new Thickness(_globalToken.PaddingXS, 0);
}
#region 使 Token
public double BadgeFontHeight { get; set; }

View File

@ -18,7 +18,6 @@ public enum CountBadgeSize
Small
}
public class CountBadge : Control, IControlCustomStyle
{
public static readonly StyledProperty<string?> BadgeColorProperty
@ -52,12 +51,12 @@ public class CountBadge : Control, IControlCustomStyle
AvaloniaProperty.Register<CountBadge, TimeSpan>(
nameof(MotionDuration));
private readonly IControlCustomStyle _customStyle;
private AdornerLayer? _adornerLayer;
private bool _animating;
private CountBadgeAdorner? _badgeAdorner;
private readonly IControlCustomStyle _customStyle;
static CountBadge()
{
AffectsMeasure<CountBadge>(DecoratedTargetProperty,
@ -143,7 +142,10 @@ public class CountBadge : Control, IControlCustomStyle
public sealed override void ApplyTemplate()
{
base.ApplyTemplate();
if (DecoratedTarget is null) CreateBadgeAdorner();
if (DecoratedTarget is null)
{
CreateBadgeAdorner();
}
}
private CountBadgeAdorner CreateBadgeAdorner()
@ -153,7 +155,10 @@ public class CountBadge : Control, IControlCustomStyle
_badgeAdorner = new CountBadgeAdorner();
_customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged();
if (BadgeColor is not null) SetupBadgeColor(BadgeColor);
if (BadgeColor is not null)
{
SetupBadgeColor(BadgeColor);
}
}
return _badgeAdorner;
@ -167,7 +172,11 @@ public class CountBadge : Control, IControlCustomStyle
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
// 这里需要抛出异常吗?
if (_adornerLayer == null) return;
if (_adornerLayer == null)
{
return;
}
AdornerLayer.SetAdornedElement(badgeAdorner, this);
AdornerLayer.SetIsClipEnabled(badgeAdorner, false);
_adornerLayer.Children.Add(badgeAdorner);
@ -178,7 +187,11 @@ public class CountBadge : Control, IControlCustomStyle
{
PrepareAdorner();
if (VisualRoot is null || _animating) return;
if (VisualRoot is null || _animating)
{
return;
}
_animating = true;
var director = Director.Instance;
@ -213,14 +226,22 @@ public class CountBadge : Control, IControlCustomStyle
private void HideAdorner()
{
// 这里需要抛出异常吗?
if (_adornerLayer is null || _badgeAdorner is null) return;
if (_adornerLayer is null || _badgeAdorner is null)
{
return;
}
_adornerLayer.Children.Remove(_badgeAdorner);
_adornerLayer = null;
}
private void HideAdornerWithMotion()
{
if (VisualRoot is null || _animating) return;
if (VisualRoot is null || _animating)
{
return;
}
_animating = true;
var director = Director.Instance;
AbstractMotion motion;
@ -291,7 +312,11 @@ public class CountBadge : Control, IControlCustomStyle
var badgeIsVisible = e.GetNewValue<bool>();
if (badgeIsVisible)
{
if (_adornerLayer is not null) return;
if (_adornerLayer is not null)
{
return;
}
PrepareAdorner();
}
else
@ -304,7 +329,11 @@ public class CountBadge : Control, IControlCustomStyle
var badgeIsVisible = e.GetNewValue<bool>();
if (badgeIsVisible)
{
if (_adornerLayer is not null) return;
if (_adornerLayer is not null)
{
return;
}
PrepareAdornerWithMotion();
}
else
@ -315,17 +344,28 @@ public class CountBadge : Control, IControlCustomStyle
if (VisualRoot is not null)
{
if (e.Property == DecoratedTargetProperty) HandleDecoratedTargetChanged();
if (e.Property == DecoratedTargetProperty)
{
HandleDecoratedTargetChanged();
}
if (e.Property == BadgeColorProperty) SetupBadgeColor(e.GetNewValue<string>());
if (e.Property == BadgeColorProperty)
{
SetupBadgeColor(e.GetNewValue<string>());
}
}
if (e.Property == CountProperty)
{
var newCount = e.GetNewValue<int>();
if (newCount == 0 && !ShowZero)
BadgeIsVisible = false;
else if (newCount > 0) BadgeIsVisible = true;
{
BadgeIsVisible = false;
}
else if (newCount > 0)
{
BadgeIsVisible = true;
}
}
}
@ -334,12 +374,17 @@ public class CountBadge : Control, IControlCustomStyle
colorStr = colorStr.Trim().ToLower();
foreach (var presetColor in PresetPrimaryColor.AllColorTypes())
{
if (presetColor.Type.ToString().ToLower() == colorStr)
{
_badgeAdorner!.BadgeColor = new SolidColorBrush(presetColor.Color());
return;
}
}
if (Color.TryParse(colorStr, out var color)) _badgeAdorner!.BadgeColor = new SolidColorBrush(color);
if (Color.TryParse(colorStr, out var color))
{
_badgeAdorner!.BadgeColor = new SolidColorBrush(color);
}
}
}

View File

@ -74,11 +74,12 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
o => o.Size,
(o, v) => o.Size = v);
private readonly IControlCustomStyle _customStyle;
private readonly List<FormattedText> _formattedTexts;
private BoxShadows _boxShadows;
private string? _countText;
private Size _countTextSize;
private readonly IControlCustomStyle _customStyle;
private readonly List<FormattedText> _formattedTexts;
private bool _initialized;
@ -217,7 +218,10 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (Styles.Count == 0) _customStyle.BuildStyles();
if (Styles.Count == 0)
{
_customStyle.BuildStyles();
}
}
public override void ApplyTemplate()
@ -236,6 +240,7 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
private void BuildBoxShadow()
{
if (BadgeShadowColor is not null)
{
_boxShadows = new BoxShadows(new BoxShadow
{
OffsetX = 0,
@ -244,6 +249,7 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
Spread = BadgeShadowSize,
Color = ((SolidColorBrush)BadgeShadowColor).Color
});
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -253,7 +259,9 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
{
if (e.Property == BadgeShadowSizeProperty ||
e.Property == BadgeShadowColorProperty)
{
BuildBoxShadow();
}
if (e.Property == CountProperty || e.Property == OverflowCountProperty)
{
@ -266,7 +274,10 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
protected override Size MeasureOverride(Size availableSize)
{
if (IsAdornerMode) return availableSize;
if (IsAdornerMode)
{
return availableSize;
}
return GetBadgePillSize();
}
@ -278,7 +289,10 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
if (_countText?.Length > 1)
{
targetWidth += PaddingInline;
if (Count > _overflowCount) targetWidth += PaddingInline;
if (Count > _overflowCount)
{
targetWidth += PaddingInline;
}
}
targetWidth = Math.Max(targetWidth, _countTextSize.Width);
@ -305,9 +319,13 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
private void BuildCountText()
{
if (Count > _overflowCount)
{
_countText = $"{_overflowCount}+";
}
else
{
_countText = $"{Count}";
}
}
public override void Render(DrawingContext context)
@ -329,9 +347,13 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
{
Point origin;
if (AnimationRenderTransformOrigin.HasValue)
{
origin = AnimationRenderTransformOrigin.Value.ToPixels(badgeRect.Size);
}
else
{
origin = RenderTransformOrigin.ToPixels(badgeRect.Size);
}
var offset = Matrix.CreateTranslation(new Point(origin.X + offsetX, origin.Y + offsetY));
var renderTransform = -offset * RenderTransform.Value * offset;
@ -341,7 +363,7 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
context.DrawPilledRect(BadgeColor, null, badgeRect, Orientation.Horizontal, _boxShadows);
// 计算合适的文字 x 坐标
var textOffsetX = offsetX + (badgeSize.Width - _countTextSize.Width) / 2;
var textOffsetX = offsetX + (badgeSize.Width - _countTextSize.Width) / 2;
var textOffsetY = offsetY + (badgeSize.Height - _countTextSize.Height) / 2;
foreach (var formattedText in _formattedTexts)
{
@ -360,12 +382,18 @@ internal class CountBadgeAdorner : Control, IControlCustomStyle
if (Count > _overflowCount)
// 生成一个即可
{
_formattedTexts.Add(BuildFormattedText(_countText));
}
else
// 没有数字都生成一个
{
foreach (var c in _countText)
{
_formattedTexts.Add(BuildFormattedText(c.ToString()));
}
}
}
}
}

View File

@ -51,7 +51,6 @@ internal class CountBadgeZoomBadgeIn : AbstractMotion
}
}
internal class CountBadgeZoomBadgeOut : AbstractMotion
{
public CountBadgeZoomBadgeOut()
@ -98,7 +97,6 @@ internal class CountBadgeZoomBadgeOut : AbstractMotion
}
}
internal class CountBadgeNoWrapperZoomBadgeIn : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);
@ -134,7 +132,6 @@ internal class CountBadgeNoWrapperZoomBadgeIn : AbstractMotion
}
}
internal class CountBadgeNoWrapperZoomBadgeOut : AbstractMotion
{
public MotionConfig? OpacityConfig => GetMotionConfig(MotionOpacityProperty);

View File

@ -21,7 +21,6 @@ public enum DotBadgeStatus
Warning
}
public class DotBadge : Control, IControlCustomStyle
{
public static readonly StyledProperty<string?> DotColorProperty
@ -49,13 +48,14 @@ public class DotBadge : Control, IControlCustomStyle
AvaloniaProperty.Register<CountBadge, TimeSpan>(
nameof(MotionDuration));
private AdornerLayer? _adornerLayer;
private bool _animating;
private readonly IControlCustomStyle _customStyle;
private DotBadgeAdorner? _dotBadgeAdorner;
private readonly bool _initialized = false;
private AdornerLayer? _adornerLayer;
private bool _animating;
private DotBadgeAdorner? _dotBadgeAdorner;
static DotBadge()
{
AffectsMeasure<DotBadge>(DecoratedTargetProperty, TextProperty);
@ -135,7 +135,10 @@ public class DotBadge : Control, IControlCustomStyle
_dotBadgeAdorner = new DotBadgeAdorner();
_customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged();
if (DotColor is not null) SetupDotColor(DotColor);
if (DotColor is not null)
{
SetupDotColor(DotColor);
}
}
return _dotBadgeAdorner;
@ -149,7 +152,11 @@ public class DotBadge : Control, IControlCustomStyle
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
// 这里需要抛出异常吗?
if (_adornerLayer == null) return;
if (_adornerLayer == null)
{
return;
}
AdornerLayer.SetAdornedElement(dotBadgeAdorner, this);
AdornerLayer.SetIsClipEnabled(dotBadgeAdorner, false);
_adornerLayer.Children.Add(dotBadgeAdorner);
@ -160,7 +167,11 @@ public class DotBadge : Control, IControlCustomStyle
{
PrepareAdorner();
if (VisualRoot is null || _animating) return;
if (VisualRoot is null || _animating)
{
return;
}
_animating = true;
var director = Director.Instance;
var motion = new CountBadgeZoomBadgeIn();
@ -180,7 +191,10 @@ public class DotBadge : Control, IControlCustomStyle
private void HideAdorner()
{
// 这里需要抛出异常吗?
if (_adornerLayer is null || _dotBadgeAdorner is null) return;
if (_adornerLayer is null || _dotBadgeAdorner is null)
{
return;
}
_adornerLayer.Children.Remove(_dotBadgeAdorner);
_adornerLayer = null;
@ -188,7 +202,11 @@ public class DotBadge : Control, IControlCustomStyle
private void HideAdornerWithMotion()
{
if (VisualRoot is null || _animating) return;
if (VisualRoot is null || _animating)
{
return;
}
_animating = true;
var director = Director.Instance;
var motion = new CountBadgeZoomBadgeOut();
@ -234,7 +252,10 @@ public class DotBadge : Control, IControlCustomStyle
public sealed override void ApplyTemplate()
{
base.ApplyTemplate();
if (DecoratedTarget is null) CreateDotBadgeAdorner();
if (DecoratedTarget is null)
{
CreateDotBadgeAdorner();
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -245,7 +266,11 @@ public class DotBadge : Control, IControlCustomStyle
var badgeIsVisible = e.GetNewValue<bool>();
if (badgeIsVisible)
{
if (_adornerLayer is not null) return;
if (_adornerLayer is not null)
{
return;
}
PrepareAdorner();
}
else
@ -258,27 +283,44 @@ public class DotBadge : Control, IControlCustomStyle
var badgeIsVisible = e.GetNewValue<bool>();
if (badgeIsVisible)
{
if (_adornerLayer is not null) return;
if (_adornerLayer is not null)
{
return;
}
if (DecoratedTarget is not null)
{
PrepareAdornerWithMotion();
}
else
{
PrepareAdorner();
}
}
else
{
if (DecoratedTarget is not null)
{
HideAdornerWithMotion();
}
else
{
HideAdorner();
}
}
}
if (_initialized)
{
if (e.Property == DecoratedTargetProperty) HandleDecoratedTargetChanged();
if (e.Property == DecoratedTargetProperty)
{
HandleDecoratedTargetChanged();
}
if (e.Property == DotColorProperty) SetupDotColor(e.GetNewValue<string>());
if (e.Property == DotColorProperty)
{
SetupDotColor(e.GetNewValue<string>());
}
}
}
@ -287,12 +329,17 @@ public class DotBadge : Control, IControlCustomStyle
colorStr = colorStr.Trim().ToLower();
foreach (var presetColor in PresetPrimaryColor.AllColorTypes())
{
if (presetColor.Type.ToString().ToLower() == colorStr)
{
_dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(presetColor.Color());
return;
}
}
if (Color.TryParse(colorStr, out var color)) _dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(color);
if (Color.TryParse(colorStr, out var color))
{
_dotBadgeAdorner!.BadgeDotColor = new SolidColorBrush(color);
}
}
}

View File

@ -56,9 +56,10 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
AvaloniaProperty.Register<DotBadgeAdorner, Point>(
nameof(Offset));
private BoxShadows _boxShadows;
private readonly IControlCustomStyle _customStyle;
private BoxShadows _boxShadows;
private bool _initialized;
private bool _isAdornerMode;
@ -146,7 +147,10 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
void IControlCustomStyle.BuildStyles()
{
if (Styles.Count == 0) BuildBadgeColorStyle();
if (Styles.Count == 0)
{
BuildBadgeColorStyle();
}
}
public sealed override void ApplyTemplate()
@ -230,7 +234,10 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
targetWidth += StatusSize;
targetWidth += textSize.Width;
targetHeight += Math.Max(textSize.Height, StatusSize);
if (textSize.Width > 0) targetWidth += BadgeTextMarginInline;
if (textSize.Width > 0)
{
targetWidth += BadgeTextMarginInline;
}
}
return new Size(targetWidth, targetHeight);
@ -242,9 +249,13 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
{
double textOffsetX = 0;
if (IsAdornerMode)
{
textOffsetX += DotSize;
}
else
{
textOffsetX += StatusSize;
}
textOffsetX += BadgeTextMarginInline;
var textRect = new Rect(new Point(textOffsetX, 0), _textLabel!.DesiredSize);
@ -259,8 +270,11 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
base.OnPropertyChanged(e);
if (e.Property == IsAdornerModeProperty)
{
var newValue = e.GetNewValue<bool>();
if (_textLabel is not null) _textLabel.IsVisible = !newValue;
var newValue = e.GetNewValue<bool>();
if (_textLabel is not null)
{
_textLabel.IsVisible = !newValue;
}
}
else if (e.Property == BadgeShadowSizeProperty ||
e.Property == BadgeShadowColorProperty)
@ -273,9 +287,13 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
{
var dotSize = 0d;
if (IsAdornerMode)
{
dotSize = DotSize;
}
else
{
dotSize = StatusSize;
}
var offsetX = 0d;
var offsetY = 0d;
@ -297,9 +315,13 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
{
Point origin;
if (AnimationRenderTransformOrigin.HasValue)
{
origin = AnimationRenderTransformOrigin.Value.ToPixels(dotRect.Size);
}
else
{
origin = RenderTransformOrigin.ToPixels(dotRect.Size);
}
var offset = Matrix.CreateTranslation(new Point(origin.X + offsetX, origin.Y + offsetY));
var renderTransform = -offset * RenderTransform.Value * offset;
@ -312,6 +334,7 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
private void BuildBoxShadow()
{
if (BadgeShadowColor is not null)
{
_boxShadows = new BoxShadows(new BoxShadow
{
OffsetX = 0,
@ -320,5 +343,6 @@ internal class DotBadgeAdorner : Control, IControlCustomStyle
Spread = BadgeShadowSize,
Color = ((SolidColorBrush)BadgeShadowColor).Color
});
}
}
}

View File

@ -15,7 +15,6 @@ public enum RibbonBadgePlacement
End
}
public class RibbonBadge : Control, IControlCustomStyle
{
public static readonly StyledProperty<string?> RibbonColorProperty
@ -38,9 +37,9 @@ public class RibbonBadge : Control, IControlCustomStyle
public static readonly StyledProperty<bool> BadgeIsVisibleProperty =
AvaloniaProperty.Register<RibbonBadge, bool>(nameof(BadgeIsVisible));
private AdornerLayer? _adornerLayer;
private readonly IControlCustomStyle _customStyle;
private AdornerLayer? _adornerLayer;
private RibbonBadgeAdorner? _ribbonBadgeAdorner;
static RibbonBadge()
@ -126,19 +125,27 @@ public class RibbonBadge : Control, IControlCustomStyle
colorStr = colorStr.Trim().ToLower();
foreach (var presetColor in PresetPrimaryColor.AllColorTypes())
{
if (presetColor.Type.ToString().ToLower() == colorStr)
{
_ribbonBadgeAdorner!.RibbonColor = new SolidColorBrush(presetColor.Color());
return;
}
}
if (Color.TryParse(colorStr, out var color)) _ribbonBadgeAdorner!.RibbonColor = new SolidColorBrush(color);
if (Color.TryParse(colorStr, out var color))
{
_ribbonBadgeAdorner!.RibbonColor = new SolidColorBrush(color);
}
}
public sealed override void ApplyTemplate()
{
base.ApplyTemplate();
if (DecoratedTarget is null) CreateBadgeAdorner();
if (DecoratedTarget is null)
{
CreateBadgeAdorner();
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -150,7 +157,11 @@ public class RibbonBadge : Control, IControlCustomStyle
var badgeIsVisible = e.GetNewValue<bool>();
if (badgeIsVisible)
{
if (_adornerLayer is not null) return;
if (_adornerLayer is not null)
{
return;
}
PrepareAdorner();
}
else
@ -161,9 +172,15 @@ public class RibbonBadge : Control, IControlCustomStyle
if (VisualRoot is not null)
{
if (e.Property == DecoratedTargetProperty) HandleDecoratedTargetChanged();
if (e.Property == DecoratedTargetProperty)
{
HandleDecoratedTargetChanged();
}
if (e.Property == RibbonColorProperty) SetupRibbonColor(e.GetNewValue<string>());
if (e.Property == RibbonColorProperty)
{
SetupRibbonColor(e.GetNewValue<string>());
}
}
}
@ -174,7 +191,10 @@ public class RibbonBadge : Control, IControlCustomStyle
_ribbonBadgeAdorner = new RibbonBadgeAdorner();
_customStyle.SetupTokenBindings();
HandleDecoratedTargetChanged();
if (RibbonColor is not null) SetupRibbonColor(RibbonColor);
if (RibbonColor is not null)
{
SetupRibbonColor(RibbonColor);
}
}
return _ribbonBadgeAdorner;
@ -188,7 +208,11 @@ public class RibbonBadge : Control, IControlCustomStyle
_adornerLayer = AdornerLayer.GetAdornerLayer(this);
// 这里需要抛出异常吗?
if (_adornerLayer == null) return;
if (_adornerLayer == null)
{
return;
}
AdornerLayer.SetAdornedElement(ribbonBadgeAdorner, this);
AdornerLayer.SetIsClipEnabled(ribbonBadgeAdorner, false);
_adornerLayer.Children.Add(ribbonBadgeAdorner);
@ -198,7 +222,10 @@ public class RibbonBadge : Control, IControlCustomStyle
private void HideAdorner()
{
// 这里需要抛出异常吗?
if (_adornerLayer is null || _ribbonBadgeAdorner is null) return;
if (_adornerLayer is null || _ribbonBadgeAdorner is null)
{
return;
}
_adornerLayer.Children.Remove(_ribbonBadgeAdorner);
_adornerLayer = null;

View File

@ -50,8 +50,8 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
(o, v) => o.IsAdornerMode = v);
private readonly BorderRenderHelper _borderRenderHelper;
private Geometry? _cornerGeometry;
private readonly IControlCustomStyle _customStyle;
private Geometry? _cornerGeometry;
private bool _initialized;
private bool _isAdornerMode;
@ -143,7 +143,10 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
if (Styles.Count == 0) _customStyle.BuildStyles();
if (Styles.Count == 0)
{
_customStyle.BuildStyles();
}
}
public sealed override void ApplyTemplate()
@ -182,7 +185,10 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
protected override Size ArrangeOverride(Size finalSize)
{
if (_textBlock is not null) _textBlock.Arrange(GetTextRect());
if (_textBlock is not null)
{
_textBlock.Arrange(GetTextRect());
}
return finalSize;
}
@ -191,8 +197,12 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
{
base.OnPropertyChanged(e);
if (VisualRoot is not null)
{
if (e.Property == PlacementProperty)
{
BuildCornerGeometry(true);
}
}
}
public override void Render(DrawingContext context)
@ -231,7 +241,10 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
private Rect GetTextRect()
{
if (_textBlock is null) return default;
if (_textBlock is null)
{
return default;
}
var offsetX = 0d;
var offsetY = 0d;
@ -239,9 +252,13 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
{
offsetY += BadgeRibbonOffset.Y;
if (Placement == RibbonBadgePlacement.End)
{
offsetX = DesiredSize.Width - _textBlock.DesiredSize.Width + BadgeRibbonOffset.X;
}
else
{
offsetX = -BadgeRibbonOffset.X;
}
}
return new Rect(new Point(offsetX, offsetY), _textBlock.DesiredSize);
@ -249,7 +266,10 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
private Rect GetCornerRect()
{
if (_cornerGeometry is null) return default;
if (_cornerGeometry is null)
{
return default;
}
var targetWidth = _cornerGeometry.Bounds.Width;
var targetHeight = _cornerGeometry.Bounds.Height;
@ -258,12 +278,18 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
if (!IsAdornerMode)
{
offsetY = DesiredSize.Height - targetHeight;
if (Placement == RibbonBadgePlacement.End) offsetX = DesiredSize.Width - targetWidth;
if (Placement == RibbonBadgePlacement.End)
{
offsetX = DesiredSize.Width - targetWidth;
}
}
else
{
var textRect = GetTextRect();
if (Placement == RibbonBadgePlacement.End) offsetX = textRect.Right - targetWidth;
var textRect = GetTextRect();
if (Placement == RibbonBadgePlacement.End)
{
offsetX = textRect.Right - targetWidth;
}
offsetY = textRect.Bottom;
}
@ -288,9 +314,15 @@ internal class RibbonBadgeAdorner : Control, IControlCustomStyle
context.EndFigure(true);
_cornerGeometry = geometryStream;
var transforms = new TransformGroup();
if (BadgeRibbonCornerTransform is not null) transforms.Children.Add(BadgeRibbonCornerTransform);
if (BadgeRibbonCornerTransform is not null)
{
transforms.Children.Add(BadgeRibbonCornerTransform);
}
if (Placement == RibbonBadgePlacement.Start) transforms.Children.Add(new ScaleTransform(-1, 1));
if (Placement == RibbonBadgePlacement.Start)
{
transforms.Children.Add(new ScaleTransform(-1, 1));
}
_cornerGeometry.Transform = transforms;
}

View File

@ -6,7 +6,6 @@ namespace AtomUI.Controls;
using AvaloniaButtonSpinner = Avalonia.Controls.ButtonSpinner;
public class ButtonSpinner : AvaloniaButtonSpinner
{
private ButtonSpinnerDecoratedBox? _decoratedBox;
@ -17,8 +16,13 @@ public class ButtonSpinner : AvaloniaButtonSpinner
{
base.OnPropertyChanged(change);
if (change.Property == CornerRadiusProperty)
{
SetupSpinnerHandleCornerRadius();
else if (change.Property == ButtonSpinnerLocationProperty) SetupSpinnerHandleCornerRadius();
}
else if (change.Property == ButtonSpinnerLocationProperty)
{
SetupSpinnerHandleCornerRadius();
}
}
private void SetupSpinnerHandleCornerRadius()
@ -26,15 +30,19 @@ public class ButtonSpinner : AvaloniaButtonSpinner
if (_spinnerHandleDecorator is not null)
{
if (ButtonSpinnerLocation == Location.Left)
{
_spinnerHandleDecorator.CornerRadius = new CornerRadius(CornerRadius.TopLeft,
0,
0,
CornerRadius.BottomLeft);
}
else
{
_spinnerHandleDecorator.CornerRadius = new CornerRadius(0,
CornerRadius.TopRight,
CornerRadius.BottomRight,
0);
}
}
}
@ -52,8 +60,6 @@ public class ButtonSpinner : AvaloniaButtonSpinner
SetupSpinnerHandleCornerRadius();
}
#region
public static readonly StyledProperty<object?> LeftAddOnProperty =

View File

@ -7,8 +7,6 @@ internal class ButtonSpinnerDecoratedBox : AddOnDecoratedBox
{
protected override Type StyleKeyOverride => typeof(AddOnDecoratedBox);
#region
internal static readonly DirectProperty<ButtonSpinnerDecoratedBox, Location> ButtonSpinnerLocationProperty =

View File

@ -27,11 +27,15 @@ internal class ButtonSpinnerInnerBox : AddOnDecoratedInnerBox, ICustomHitTest
{
var padding = _spinnerHandleWidthToken + InnerBoxPadding.Right;
if (ButtonSpinnerLocation == Location.Right)
{
EffectiveInnerBoxPadding = new Thickness(InnerBoxPadding.Left, InnerBoxPadding.Top, padding,
InnerBoxPadding.Bottom);
}
else
{
EffectiveInnerBoxPadding = new Thickness(padding, InnerBoxPadding.Top, InnerBoxPadding.Right,
InnerBoxPadding.Bottom);
}
}
else
{
@ -77,8 +81,6 @@ internal class ButtonSpinnerInnerBox : AddOnDecoratedInnerBox, ICustomHitTest
}
}
#region
public static readonly StyledProperty<object?> SpinnerContentProperty =
@ -92,8 +94,6 @@ internal class ButtonSpinnerInnerBox : AddOnDecoratedInnerBox, ICustomHitTest
#endregion
#region
internal static readonly DirectProperty<ButtonSpinnerInnerBox, Location> ButtonSpinnerLocationProperty =

View File

@ -20,42 +20,42 @@ internal class ButtonSpinnerToken : LineEditToken
}
/// <summary>
/// 输入框宽度
/// 输入框宽度
/// </summary>
public double ControlWidth { get; set; }
/// <summary>
/// 操作按钮宽度
/// 操作按钮宽度
/// </summary>
public double HandleWidth { get; set; }
/// <summary>
/// 操作按钮图标大小
/// 操作按钮图标大小
/// </summary>
public double HandleIconSize { get; set; }
/// <summary>
/// 操作按钮背景色
/// 操作按钮背景色
/// </summary>
public Color HandleBg { get; set; }
/// <summary>
/// 操作按钮激活背景色
/// 操作按钮激活背景色
/// </summary>
public Color HandleActiveBg { get; set; }
/// <summary>
/// 操作按钮悬浮颜色
/// 操作按钮悬浮颜色
/// </summary>
public Color HandleHoverColor { get; set; }
/// <summary>
/// 操作按钮边框颜色
/// 操作按钮边框颜色
/// </summary>
public Color HandleBorderColor { get; set; }
/// <summary>
/// 面性变体操作按钮背景色
/// 面性变体操作按钮背景色
/// </summary>
public Color FilledHandleBg { get; set; }

View File

@ -21,7 +21,6 @@ namespace AtomUI.Controls;
using AvaloniaButton = Avalonia.Controls.Button;
using ButtonSizeType = SizeType;
public enum ButtonType
{
Default,
@ -30,7 +29,6 @@ public enum ButtonType
Text
}
public enum ButtonShape
{
Default,
@ -38,15 +36,13 @@ public enum ButtonShape
Round
}
// TODO 目前不能动态切换 ButtonType
[PseudoClasses(IconOnlyPC, LoadingPC)]
public class Button : AvaloniaButton,
ISizeTypeAware,
IControlCustomStyle,
IWaveAdornerInfoProvider
ISizeTypeAware,
IControlCustomStyle,
IWaveAdornerInfoProvider
{
public const string IconOnlyPC = ":icononly";
public const string LoadingPC = ":loading";
@ -91,6 +87,7 @@ public class Button : AvaloniaButton,
if (ButtonType == ButtonType.Default)
{
if (IsDanger)
{
Effect = new DropShadowEffect
{
OffsetX = DangerShadow.OffsetX,
@ -98,7 +95,9 @@ public class Button : AvaloniaButton,
Color = DangerShadow.Color,
BlurRadius = DangerShadow.Blur
};
}
else
{
Effect = new DropShadowEffect
{
OffsetX = DefaultShadow.OffsetX,
@ -106,10 +105,12 @@ public class Button : AvaloniaButton,
Color = DefaultShadow.Color,
BlurRadius = DefaultShadow.Blur
};
}
}
else if (ButtonType == ButtonType.Primary)
{
if (IsDanger)
{
Effect = new DropShadowEffect
{
OffsetX = DangerShadow.OffsetX,
@ -117,7 +118,9 @@ public class Button : AvaloniaButton,
Color = DangerShadow.Color,
BlurRadius = DangerShadow.Blur
};
}
else
{
Effect = new DropShadowEffect
{
OffsetX = PrimaryShadow.OffsetX,
@ -125,6 +128,7 @@ public class Button : AvaloniaButton,
Color = PrimaryShadow.Color,
BlurRadius = PrimaryShadow.Blur
};
}
}
}
@ -132,9 +136,13 @@ public class Button : AvaloniaButton,
{
ControlStateUtils.InitCommonState(this, ref _styleState);
if (IsPressed)
{
_styleState |= ControlStyleState.Sunken;
}
else
{
_styleState |= ControlStyleState.Raised;
}
}
void IControlCustomStyle.SetupTransitions()
@ -182,56 +190,79 @@ public class Button : AvaloniaButton,
void IControlCustomStyle.HandlePropertyChangedForStyle(AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == IsPointerOverProperty ||
e.Property == IsPressedProperty ||
e.Property == IsPressedProperty ||
e.Property == IsEnabledProperty)
{
_customStyle.CollectStyleState();
ApplyIconModeStyleConfig();
if (e.Property == IsPressedProperty)
{
if (!IsLoading && _styleState.HasFlag(ControlStyleState.Raised) && (ButtonType == ButtonType.Primary ||
ButtonType == ButtonType.Default))
ButtonType == ButtonType.Default))
{
WaveType waveType = default;
if (Shape == ButtonShape.Default)
{
waveType = WaveType.RoundRectWave;
}
else if (Shape == ButtonShape.Round)
waveType = WaveType.PillWave;
else if (Shape == ButtonShape.Circle) waveType = WaveType.CircleWave;
{
waveType = WaveType.PillWave;
}
else if (Shape == ButtonShape.Circle)
{
waveType = WaveType.CircleWave;
}
Color? waveColor = null;
if (IsDanger)
{
if (ButtonType == ButtonType.Primary && !IsGhost)
{
waveColor = Color.Parse(Background?.ToString()!);
}
else
{
waveColor = Color.Parse(Foreground?.ToString()!);
}
}
WaveSpiritAdorner.ShowWaveAdorner(this, waveType, waveColor);
}
}
}
if (e.Property == ButtonTypeProperty)
{
if (VisualRoot is not null) SetupControlTheme();
if (VisualRoot is not null)
{
SetupControlTheme();
}
}
else if (e.Property == ContentProperty ||
e.Property == TextProperty ||
e.Property == TextProperty ||
e.Property == IsLoadingProperty)
{
UpdatePseudoClasses();
}
if (e.Property == IconProperty) SetupIcon();
if (e.Property == IconProperty)
{
SetupIcon();
}
if (e.Property == IsDangerProperty ||
e.Property == IsGhostProperty ||
e.Property == IsGhostProperty ||
e.Property == ButtonTypeProperty)
{
SetupIconBrush();
}
if (e.Property == BorderBrushProperty ||
e.Property == ButtonTypeProperty)
{
SetupEffectiveBorderThickness();
}
}
public Rect WaveGeometry()
@ -287,19 +318,29 @@ public class Button : AvaloniaButton,
private void SetupControlTheme()
{
if (ButtonType == ButtonType.Default)
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, DefaultButtonTheme.ID);
}
else if (ButtonType == ButtonType.Primary)
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, PrimaryButtonTheme.ID);
}
else if (ButtonType == ButtonType.Text)
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, TextButtonTheme.ID);
}
else if (ButtonType == ButtonType.Link)
{
TokenResourceBinder.CreateTokenBinding(this, ThemeProperty, LinkButtonTheme.ID);
}
}
private void ApplyShapeStyleConfig()
{
if (Shape == ButtonShape.Circle)
{
TokenResourceBinder.CreateTokenBinding(this, PaddingProperty, ButtonTokenResourceKey.CirclePadding);
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@ -312,16 +353,25 @@ public class Button : AvaloniaButton,
protected virtual void ApplyIconModeStyleConfig()
{
if (Icon is null) return;
if (Icon is null)
{
return;
}
if (_styleState.HasFlag(ControlStyleState.Enabled))
{
if (_styleState.HasFlag(ControlStyleState.Sunken))
{
Icon.IconMode = IconMode.Selected;
}
else if (_styleState.HasFlag(ControlStyleState.MouseOver))
{
Icon.IconMode = IconMode.Active;
}
else
{
Icon.IconMode = IconMode.Normal;
}
}
else
{
@ -348,9 +398,13 @@ public class Button : AvaloniaButton,
else if (ButtonType == ButtonType.Primary)
{
if (IsGhost)
{
EffectiveBorderThickness = BorderThickness;
}
else
{
EffectiveBorderThickness = new Thickness(0);
}
}
else
{
@ -469,9 +523,9 @@ public class Button : AvaloniaButton,
}
protected virtual void NotifyIconBrushCalculated(in TokenResourceKey normalFilledBrushKey,
in TokenResourceKey selectedFilledBrushKey,
in TokenResourceKey activeFilledBrushKey,
in TokenResourceKey disabledFilledBrushKey)
in TokenResourceKey selectedFilledBrushKey,
in TokenResourceKey activeFilledBrushKey,
in TokenResourceKey disabledFilledBrushKey)
{
}
@ -481,8 +535,6 @@ public class Button : AvaloniaButton,
PseudoClasses.Set(LoadingPC, IsLoading);
}
#region
public static readonly StyledProperty<ButtonType> ButtonTypeProperty =
@ -568,8 +620,6 @@ public class Button : AvaloniaButton,
#endregion
#region
internal static readonly StyledProperty<double> ControlHeightTokenProperty =

View File

@ -16,217 +16,217 @@ internal class ButtonToken : AbstractControlDesignToken
}
/// <summary>
/// 文字字重
/// 文字字重
/// </summary>
public int FontWeight { get; set; }
/// <summary>
/// 默认按钮阴影
/// 默认按钮阴影
/// </summary>
public BoxShadow DefaultShadow { get; set; }
/// <summary>
/// 主要按钮阴影
/// 主要按钮阴影
/// </summary>
public BoxShadow PrimaryShadow { get; set; }
/// <summary>
/// 危险按钮阴影
/// 危险按钮阴影
/// </summary>
public BoxShadow DangerShadow { get; set; }
/// <summary>
/// 主要按钮文本颜色
/// 主要按钮文本颜色
/// </summary>
public Color PrimaryColor { get; set; }
/// <summary>
/// 默认按钮文本颜色
/// 默认按钮文本颜色
/// </summary>
public Color DefaultColor { get; set; }
/// <summary>
/// 默认按钮背景色
/// 默认按钮背景色
/// </summary>
public Color DefaultBg { get; set; }
/// <summary>
/// 默认按钮边框颜色
/// 默认按钮边框颜色
/// </summary>
public Color DefaultBorderColor { get; set; }
/// <summary>
/// 默认的禁用边框颜色
/// 默认的禁用边框颜色
/// </summary>
public Color DefaultBorderColorDisabled { get; set; }
/// <summary>
/// 危险按钮文本颜色
/// 危险按钮文本颜色
/// </summary>
public Color DangerColor { get; set; }
/// <summary>
/// 默认按钮悬浮态背景色
/// 默认按钮悬浮态背景色
/// </summary>
public Color DefaultHoverBg { get; set; }
/// <summary>
/// 默认按钮悬浮态文本颜色
/// 默认按钮悬浮态文本颜色
/// </summary>
public Color DefaultHoverColor { get; set; }
/// <summary>
/// 默认按钮悬浮态边框颜色
/// 默认按钮悬浮态边框颜色
/// </summary>
public Color DefaultHoverBorderColor { get; set; }
/// <summary>
/// 默认按钮激活态背景色
/// 默认按钮激活态背景色
/// </summary>
public Color DefaultActiveBg { get; set; }
/// <summary>
/// 默认按钮激活态文字颜色
/// 默认按钮激活态文字颜色
/// </summary>
public Color DefaultActiveColor { get; set; }
/// <summary>
/// 默认按钮激活态边框颜色
/// 默认按钮激活态边框颜色
/// </summary>
public Color DefaultActiveBorderColor { get; set; }
/// <summary>
/// 禁用状态边框颜色
/// 禁用状态边框颜色
/// </summary>
public Color BorderColorDisabled { get; set; }
/// <summary>
/// 默认幽灵按钮文本颜色
/// 默认幽灵按钮文本颜色
/// </summary>
public Color DefaultGhostColor { get; set; }
/// <summary>
/// 幽灵按钮背景色
/// 幽灵按钮背景色
/// </summary>
public Color GhostBg { get; set; }
/// <summary>
/// 默认幽灵按钮边框颜色
/// 默认幽灵按钮边框颜色
/// </summary>
public Color DefaultGhostBorderColor { get; set; }
/// <summary>
/// 按钮内间距
/// 按钮内间距
/// </summary>
public Thickness Padding { get; set; }
/// <summary>
/// 大号按钮内间距
/// 大号按钮内间距
/// </summary>
public Thickness PaddingLG { get; set; }
/// <summary>
/// 小号按钮内间距
/// 小号按钮内间距
/// </summary>
public Thickness PaddingSM { get; set; }
/// <summary>
/// 按钮右边一个额外的区域对右侧的小号外边距
/// 按钮右边一个额外的区域对右侧的小号外边距
/// </summary>
public Thickness ExtraContentMarginSM { get; set; }
/// <summary>
/// 按钮右边一个额外的区域对右侧的外边距
/// 按钮右边一个额外的区域对右侧的外边距
/// </summary>
public Thickness ExtraContentMargin { get; set; }
/// <summary>
/// 按钮右边一个额外的区域对右侧的大号外边距
/// 按钮右边一个额外的区域对右侧的大号外边距
/// </summary>
public Thickness ExtraContentMarginLG { get; set; }
/// <summary>
/// 圆形按钮内间距
/// 圆形按钮内间距
/// </summary>
public Thickness CirclePadding { get; set; }
/// <summary>
/// 只有图标的按钮图标尺寸
/// 只有图标的按钮图标尺寸
/// </summary>
public double OnlyIconSize { get; set; }
/// <summary>
/// 大号只有图标的按钮图标尺寸
/// 大号只有图标的按钮图标尺寸
/// </summary>
public double OnlyIconSizeLG { get; set; }
/// <summary>
/// 小号只有图标的按钮图标尺寸
/// 小号只有图标的按钮图标尺寸
/// </summary>
public double OnlyIconSizeSM { get; set; }
/// <summary>
/// 图标的按钮图标尺寸
/// 图标的按钮图标尺寸
/// </summary>
public double IconSize { get; set; }
/// <summary>
/// 只有图标的按钮图标尺寸
/// 只有图标的按钮图标尺寸
/// </summary>
public double IconSizeLG { get; set; }
/// <summary>
/// 只有图标的按钮图标尺寸
/// 只有图标的按钮图标尺寸
/// </summary>
public double IconSizeSM { get; set; }
/// <summary>
/// 完成 Icon 外边距
/// 完成 Icon 外边距
/// </summary>
public Thickness IconMargin { get; set; }
/// <summary>
/// 按钮组边框颜色
/// 按钮组边框颜色
/// </summary>
public Color GroupBorderColor { get; set; }
/// <summary>
/// 链接按钮悬浮态背景色
/// 链接按钮悬浮态背景色
/// </summary>
public Color LinkHoverBg { get; set; }
/// <summary>
/// 文本按钮悬浮态背景色
/// 文本按钮悬浮态背景色
/// </summary>
public Color TextHoverBg { get; set; }
/// <summary>
/// 按钮内容字体大小
/// 按钮内容字体大小
/// </summary>
public double ContentFontSize { get; set; } = double.NaN;
/// <summary>
/// 大号按钮内容字体大小
/// 大号按钮内容字体大小
/// </summary>
public double ContentFontSizeLG { get; set; } = double.NaN;
/// <summary>
/// 小号按钮内容字体大小
/// 小号按钮内容字体大小
/// </summary>
public double ContentFontSizeSM { get; set; } = double.NaN;
/// <summary>
/// 按钮内容字体行高
/// 按钮内容字体行高
/// </summary>
public double ContentLineHeight { get; set; } = double.NaN;
/// <summary>
/// 大号按钮内容字体行高
/// 大号按钮内容字体行高
/// </summary>
public double ContentLineHeightLG { get; set; } = double.NaN;
/// <summary>
/// 小号按钮内容字体行高
/// 小号按钮内容字体行高
/// </summary>
public double ContentLineHeightSM { get; set; } = double.NaN;
@ -316,7 +316,7 @@ internal class ButtonToken : AbstractControlDesignToken
Math.Max((controlHeightLG - ContentLineHeightLG) / 2 - lineWidth, 0));
ExtraContentMarginSM = new Thickness(PaddingSM.Left / 2, 0, 0, 0);
ExtraContentMargin = new Thickness(Padding.Left / 2, 0, 0, 0);
ExtraContentMargin = new Thickness(Padding.Left / 2, 0, 0, 0);
ExtraContentMarginLG = new Thickness(PaddingLG.Left / 2, 0, 0, 0);
CirclePadding = new Thickness(PaddingSM.Left / 2);
@ -330,27 +330,25 @@ internal class ButtonToken : AbstractControlDesignToken
IconMargin = new Thickness(0, 0, _globalToken.PaddingXXS, 0);
IconOnyPadding = new Thickness(Math.Max((controlHeight - ContentLineHeight) / 2 - lineWidth, 0));
IconOnyPadding = new Thickness(Math.Max((controlHeight - ContentLineHeight) / 2 - lineWidth, 0));
IconOnyPaddingLG = new Thickness(Math.Max((controlHeightLG - ContentLineHeightLG) / 2 - lineWidth, 0));
IconOnyPaddingSM = new Thickness(Math.Max((controlHeightSM - ContentLineHeightSM) / 2 - lineWidth, 0));
}
#region Token
/// <summary>
/// IconOnly 按钮内间距
/// IconOnly 按钮内间距
/// </summary>
public Thickness IconOnyPadding { get; set; }
/// <summary>
/// IconOnly 大号按钮内间距
/// IconOnly 大号按钮内间距
/// </summary>
public Thickness IconOnyPaddingLG { get; set; }
/// <summary>
/// IconOnly 小号按钮内间距
/// IconOnly 小号按钮内间距
/// </summary>
public Thickness IconOnyPaddingSM { get; set; }

View File

@ -57,20 +57,29 @@ public class DropdownButton : Button
base.OnApplyTemplate(e);
TokenResourceBinder.CreateGlobalTokenBinding(this, MarginToAnchorProperty, GlobalTokenResourceKey.MarginXXS);
SetupFlyoutProperties();
if (IsShowIndicator) RightExtraContent = _openIndicatorIcon;
if (IsShowIndicator)
{
RightExtraContent = _openIndicatorIcon;
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (VisualRoot is not null)
{
if (e.Property == IsShowIndicatorProperty)
{
if (IsShowIndicator)
{
RightExtraContent = _openIndicatorIcon;
}
else
{
RightExtraContent = null;
}
}
}
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@ -107,12 +116,16 @@ public class DropdownButton : Button
{
var host = popupHostProvider.PopupHost;
if (host is PopupRoot popupRoot)
{
if (popupRoot.Parent is Popup popup)
{
if (popup.Child is MenuFlyoutPresenter menuFlyoutPresenter)
{
_menuFlyoutPresenter = menuFlyoutPresenter;
menuFlyoutPresenter.MenuItemClicked += HandleMenuItemClicked;
}
}
}
}
}
@ -132,9 +145,9 @@ public class DropdownButton : Button
}
protected override void NotifyIconBrushCalculated(in TokenResourceKey normalFilledBrushKey,
in TokenResourceKey selectedFilledBrushKey,
in TokenResourceKey activeFilledBrushKey,
in TokenResourceKey disabledFilledBrushKey)
in TokenResourceKey selectedFilledBrushKey,
in TokenResourceKey activeFilledBrushKey,
in TokenResourceKey disabledFilledBrushKey)
{
if (_openIndicatorIcon is not null)
{
@ -156,11 +169,17 @@ public class DropdownButton : Button
if (_styleState.HasFlag(ControlStyleState.Enabled))
{
if (_styleState.HasFlag(ControlStyleState.Sunken))
{
_openIndicatorIcon.IconMode = IconMode.Selected;
}
else if (_styleState.HasFlag(ControlStyleState.MouseOver))
{
_openIndicatorIcon.IconMode = IconMode.Active;
}
else
{
_openIndicatorIcon.IconMode = IconMode.Normal;
}
}
else
{
@ -171,8 +190,6 @@ public class DropdownButton : Button
base.ApplyIconModeStyleConfig();
}
#region
public static readonly StyledProperty<MenuFlyout?> DropdownFlyoutProperty =

View File

@ -11,7 +11,6 @@ namespace AtomUI.Controls;
using AvaloniaButton = Avalonia.Controls.Button;
public class IconButton : AvaloniaButton, ICustomHitTest
{
private ControlStyleState _styleState;
@ -46,11 +45,14 @@ public class IconButton : AvaloniaButton, ICustomHitTest
if (e.Property == IconProperty)
{
var oldIcon = e.GetOldValue<PathIcon?>();
if (oldIcon is not null) ((ISetLogicalParent)oldIcon).SetParent(null);
if (oldIcon is not null)
{
((ISetLogicalParent)oldIcon).SetParent(null);
}
SetupIcon();
}
else if (e.Property == IsPressedProperty ||
else if (e.Property == IsPressedProperty ||
e.Property == IsPointerOverProperty ||
e.Property == IsEnabledProperty)
{
@ -80,8 +82,13 @@ public class IconButton : AvaloniaButton, ICustomHitTest
{
Icon.IconMode = IconMode.Normal;
if (_styleState.HasFlag(ControlStyleState.Sunken))
Icon.IconMode = IconMode.Selected;
else if (_styleState.HasFlag(ControlStyleState.MouseOver)) Icon.IconMode = IconMode.Active;
{
Icon.IconMode = IconMode.Selected;
}
else if (_styleState.HasFlag(ControlStyleState.MouseOver))
{
Icon.IconMode = IconMode.Active;
}
}
else
{
@ -94,13 +101,15 @@ public class IconButton : AvaloniaButton, ICustomHitTest
{
ControlStateUtils.InitCommonState(this, ref _styleState);
if (IsPressed)
{
_styleState |= ControlStyleState.Sunken;
}
else
{
_styleState |= ControlStyleState.Raised;
}
}
#region
public static readonly StyledProperty<PathIcon?> IconProperty

View File

@ -53,7 +53,7 @@ internal class IconButtonTheme : BaseControlTheme
}
var enableHoverBgStyle = new Style(selector =>
selector.Nesting().PropertyEquals(IconButton.IsEnableHoverEffectProperty, true)
.Class(StdPseudoClass.PointerOver));
.Class(StdPseudoClass.PointerOver));
{
var contentStyle = new Style(selector => selector.Nesting().Template().Name(IconContentPart));
contentStyle.Add(ContentPresenter.BackgroundProperty, GlobalTokenResourceKey.ColorBgTextHover);

View File

@ -25,11 +25,11 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
internal const string pcChecked = ":checked";
internal const string pcPressed = ":pressed";
internal const string pcFlyoutOpen = ":flyout-open";
private readonly FlyoutStateHelper _flyoutStateHelper;
private bool _commandCanExecute = true;
private IDisposable? _flyoutPropertyChangedDisposable;
private readonly FlyoutStateHelper _flyoutStateHelper;
private KeyGesture? _hotkey;
private bool _isAttachedToLogicalTree;
private bool _isFlyoutOpen;
@ -74,7 +74,10 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
private void CanExecuteChanged(ICommand? command, object? parameter)
{
if (!((ILogical)this).IsAttachedToLogicalTree) return;
if (!((ILogical)this).IsAttachedToLogicalTree)
{
return;
}
var canExecute = command is null || command.CanExecute(parameter);
@ -86,7 +89,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Updates the visual state of the control by applying latest PseudoClasses.
/// Updates the visual state of the control by applying latest PseudoClasses.
/// </summary>
protected void UpdatePseudoClasses()
{
@ -101,7 +104,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Closes the secondary button's flyout.
/// Closes the secondary button's flyout.
/// </summary>
protected void CloseFlyout()
{
@ -109,7 +112,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Registers all flyout events.
/// Registers all flyout events.
/// </summary>
/// <param name="flyout">The flyout to connect events to.</param>
private void RegisterFlyoutEvents(Flyout? flyout)
@ -120,13 +123,14 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
flyout.Closed += HandleFlyoutClosed;
_flyoutPropertyChangedDisposable = flyout
.GetPropertyChangedObservable(Avalonia.Controls.Primitives.Popup.PlacementProperty)
.Subscribe(HandleFlyoutPlacementPropertyChanged);
.GetPropertyChangedObservable(Avalonia.Controls.Primitives.Popup
.PlacementProperty)
.Subscribe(HandleFlyoutPlacementPropertyChanged);
}
}
/// <summary>
/// Explicitly unregisters all flyout events.
/// Explicitly unregisters all flyout events.
/// </summary>
/// <param name="flyout">The flyout to disconnect events from.</param>
private void UnregisterFlyoutEvents(Flyout? flyout)
@ -142,11 +146,14 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Explicitly unregisters all events related to the two buttons in OnApplyTemplate().
/// Explicitly unregisters all events related to the two buttons in OnApplyTemplate().
/// </summary>
private void UnregisterEvents()
{
if (_primaryButton != null) _primaryButton.Click -= HandlePrimaryButtonClick;
if (_primaryButton != null)
{
_primaryButton.Click -= HandlePrimaryButtonClick;
}
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@ -180,13 +187,19 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
_secondaryButton = e.NameScope.Find<Button>("PART_SecondaryButton");
_flyoutStateHelper.AnchorTarget = _secondaryButton;
if (_primaryButton != null) _primaryButton.Click += HandlePrimaryButtonClick;
if (_primaryButton != null)
{
_primaryButton.Click += HandlePrimaryButtonClick;
}
if (FlyoutButtonIcon is null)
{
FlyoutButtonIcon = new PathIcon
{
Kind = "EllipsisOutlined"
};
}
SetupEffectiveButtonType();
SetupFlyoutProperties();
RegisterFlyoutEvents(Flyout);
@ -239,7 +252,10 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
_hotkey = HotKey;
SetCurrentValue(HotKeyProperty, null);
if (Command != null) Command.CanExecuteChanged -= CanExecuteChanged;
if (Command != null)
{
Command.CanExecuteChanged -= CanExecuteChanged;
}
_isAttachedToLogicalTree = false;
}
@ -254,9 +270,15 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
if (_isAttachedToLogicalTree)
{
if (oldValue is ICommand oldCommand) oldCommand.CanExecuteChanged -= CanExecuteChanged;
if (oldValue is ICommand oldCommand)
{
oldCommand.CanExecuteChanged -= CanExecuteChanged;
}
if (newValue is ICommand newCommand) newCommand.CanExecuteChanged += CanExecuteChanged;
if (newValue is ICommand newCommand)
{
newCommand.CanExecuteChanged += CanExecuteChanged;
}
}
CanExecuteChanged(newValue, CommandParameter);
@ -272,7 +294,10 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
// If flyout is changed while one is already open, make sure we
// close the old one first
// This is the same behavior as Button
if (oldFlyout != null && oldFlyout.IsOpen) oldFlyout.Hide();
if (oldFlyout != null && oldFlyout.IsOpen)
{
oldFlyout.Hide();
}
// Must unregister events here while a reference to the old flyout still exists
UnregisterFlyoutEvents(oldFlyout);
@ -295,9 +320,13 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
private void SetupEffectiveButtonType()
{
if (IsPrimaryButtonType)
{
EffectiveButtonType = ButtonType.Primary;
}
else
{
EffectiveButtonType = ButtonType.Default;
}
}
private void SetupButtonCornerRadius()
@ -366,7 +395,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Invokes the <see cref="Click" /> event when the primary button part is clicked.
/// Invokes the <see cref="Click" /> event when the primary button part is clicked.
/// </summary>
/// <param name="e">The event args from the internal Click event.</param>
protected virtual void OnClickPrimary(RoutedEventArgs? e)
@ -388,7 +417,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Invoked when the split button's flyout is opened.
/// Invoked when the split button's flyout is opened.
/// </summary>
protected virtual void OnFlyoutOpened()
{
@ -396,7 +425,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Invoked when the split button's flyout is closed.
/// Invoked when the split button's flyout is closed.
/// </summary>
protected virtual void OnFlyoutClosed()
{
@ -404,7 +433,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Event handler for when the internal primary button part is clicked.
/// Event handler for when the internal primary button part is clicked.
/// </summary>
private void HandlePrimaryButtonClick(object? sender, RoutedEventArgs e)
{
@ -414,7 +443,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Called when the <see cref="PopupFlyoutBase.Placement" /> property changes.
/// Called when the <see cref="PopupFlyoutBase.Placement" /> property changes.
/// </summary>
private void HandleFlyoutPlacementPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
@ -422,13 +451,12 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Event handler for when the split button's flyout is opened.
/// Event handler for when the split button's flyout is opened.
/// </summary>
private void HandleFlyoutOpened(object? sender, EventArgs e)
{
var flyout = sender as Flyout;
// It is possible to share flyouts among multiple controls including SplitButton.
// This can cause a problem here since all controls that share a flyout receive
// the same Opened/Closed events at the same time.
@ -445,7 +473,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Event handler for when the split button's flyout is closed.
/// Event handler for when the split button's flyout is closed.
/// </summary>
private void HandleFlyoutClosed(object? sender, EventArgs e)
{
@ -463,20 +491,27 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
protected override Size ArrangeOverride(Size finalSize)
{
var size = base.ArrangeOverride(finalSize);
if (_originRect is null) _originRect = _secondaryButton?.Bounds;
var size = base.ArrangeOverride(finalSize);
if (_originRect is null)
{
_originRect = _secondaryButton?.Bounds;
}
if (!IsPrimaryButtonType)
{
if (_secondaryButton is not null && _originRect.HasValue)
{
_secondaryButton.Arrange(
_originRect.Value.Inflate(new Thickness(_secondaryButton.BorderThickness.Left, 0, 0, 0)));
}
}
else
{
if (_secondaryButton is not null && _originRect.HasValue)
{
_secondaryButton.Arrange(
_originRect.Value.Deflate(new Thickness(_secondaryButton.BorderThickness.Left, 0, 0, 0)));
}
}
return size;
@ -485,10 +520,15 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
public override void Render(DrawingContext context)
{
if (IsPrimaryButtonType)
{
if (_secondaryButton is not null)
{
var offset = _secondaryButton.TranslatePoint(new Point(0, 0), this);
if (!offset.HasValue) return;
if (!offset.HasValue)
{
return;
}
using var optionState = context.PushRenderOptions(new RenderOptions
{
EdgeMode = EdgeMode.Aliased
@ -497,10 +537,9 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
var endPoint = new Point(offset.Value.X, Bounds.Height);
context.DrawLine(new Pen(BorderBrush, BorderThickness.Left), startPoint, endPoint);
}
}
}
#region
public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
@ -566,7 +605,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
AvaloniaProperty.Register<SplitButton, bool>(nameof(IsPrimaryButtonType));
/// <summary>
/// Raised when the user presses the primary part of the <see cref="SplitButton" />.
/// Raised when the user presses the primary part of the <see cref="SplitButton" />.
/// </summary>
public event EventHandler<RoutedEventArgs>? Click
{
@ -581,7 +620,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Gets or sets a parameter to be passed to the <see cref="Command" />.
/// Gets or sets a parameter to be passed to the <see cref="Command" />.
/// </summary>
public object? CommandParameter
{
@ -590,7 +629,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Gets or sets the <see cref="Flyout" /> that is shown when the secondary part is pressed.
/// Gets or sets the <see cref="Flyout" /> that is shown when the secondary part is pressed.
/// </summary>
public Flyout? Flyout
{
@ -599,7 +638,7 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
}
/// <summary>
/// Gets or sets an <see cref="KeyGesture" /> associated with this control
/// Gets or sets an <see cref="KeyGesture" /> associated with this control
/// </summary>
public KeyGesture? HotKey
{
@ -699,8 +738,6 @@ public class SplitButton : ContentControl, ICommandSource, ISizeTypeAware
#endregion
#region
internal static readonly DirectProperty<SplitButton, CornerRadius> PrimaryButtonCornerRadiusProperty =

View File

@ -103,7 +103,7 @@ internal class SplitButtonTheme : BaseControlTheme
Add(buttonStyle);
var buttonHoverStyle = new Style(selector =>
selector.Nesting().Template().Name(MainLayoutPart).Child().OfType<Button>()
.Class(StdPseudoClass.PointerOver));
.Class(StdPseudoClass.PointerOver));
buttonHoverStyle.Add(Visual.ZIndexProperty, ActivatedZIndex);
Add(buttonHoverStyle);
}

View File

@ -28,9 +28,16 @@ public class ToggleIconButton : ToggleButton
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (CheckedIcon is not null) ConfigureIcon(CheckedIcon);
if (CheckedIcon is not null)
{
ConfigureIcon(CheckedIcon);
}
if (UnCheckedIcon is not null)
{
ConfigureIcon(UnCheckedIcon);
}
if (UnCheckedIcon is not null) ConfigureIcon(UnCheckedIcon);
ApplyIconToContent();
}
@ -63,8 +70,13 @@ public class ToggleIconButton : ToggleButton
{
pathIcon.IconMode = IconMode.Normal;
if (_styleState.HasFlag(ControlStyleState.Sunken))
{
pathIcon.IconMode = IconMode.Selected;
else if (_styleState.HasFlag(ControlStyleState.MouseOver)) pathIcon.IconMode = IconMode.Active;
}
else if (_styleState.HasFlag(ControlStyleState.MouseOver))
{
pathIcon.IconMode = IconMode.Active;
}
}
else
{
@ -76,28 +88,38 @@ public class ToggleIconButton : ToggleButton
if (change.Property == CheckedIconProperty ||
change.Property == UnCheckedIconProperty)
{
if (change.NewValue is PathIcon newIcon)
{
ConfigureIcon(newIcon);
ApplyIconToContent();
}
}
}
internal virtual void ApplyIconToContent()
{
if (IsChecked.HasValue && IsChecked.Value)
{
Content = CheckedIcon;
}
else
{
Content = UnCheckedIcon;
}
}
private void CollectStyleState()
{
ControlStateUtils.InitCommonState(this, ref _styleState);
if (IsPressed)
{
_styleState |= ControlStyleState.Sunken;
}
else
{
_styleState |= ControlStyleState.Raised;
}
}
public bool HitTest(Point point)
@ -110,8 +132,6 @@ public class ToggleIconButton : ToggleButton
return true;
}
#region
public static readonly StyledProperty<PathIcon?> CheckedIconProperty

View File

@ -18,11 +18,10 @@ namespace AtomUI.Controls;
using AvaloniaCheckBox = Avalonia.Controls.CheckBox;
public class CheckBox : AvaloniaCheckBox,
ICustomHitTest,
IWaveAdornerInfoProvider,
IControlCustomStyle
ICustomHitTest,
IWaveAdornerInfoProvider,
IControlCustomStyle
{
internal static readonly StyledProperty<double> CheckIndicatorSizeProperty =
AvaloniaProperty.Register<CheckBox, double>(nameof(CheckIndicatorSize));
@ -168,7 +167,10 @@ public class CheckBox : AvaloniaCheckBox,
for (var i = 0; i < visualCount; i++)
{
var visual = visualChildren[i];
if (visual is Layoutable layoutable) layoutable.Arrange(arrangeRect);
if (visual is Layoutable layoutable)
{
layoutable.Arrange(arrangeRect);
}
}
return finalSize;
@ -207,8 +209,6 @@ public class CheckBox : AvaloniaCheckBox,
}
}
#region IControlCustomStyle
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@ -246,9 +246,13 @@ public class CheckBox : AvaloniaCheckBox,
}
if (IsPressed)
{
_styleState |= ControlStyleState.Sunken;
}
else
{
_styleState |= ControlStyleState.Raised;
}
}
// Measure 之后才有值
@ -259,7 +263,7 @@ public class CheckBox : AvaloniaCheckBox,
private Rect TextRect()
{
var offsetX = CheckIndicatorSize + PaddingInline;
var offsetX = CheckIndicatorSize + PaddingInline;
return new Rect(offsetX, 0d, DesiredSize.Width - offsetX, DesiredSize.Height);
}
@ -268,15 +272,24 @@ public class CheckBox : AvaloniaCheckBox,
if (_styleState.HasFlag(ControlStyleState.Enabled))
{
if (_styleState.HasFlag(ControlStyleState.On))
{
IndicatorCheckedMarkEffectSize = CheckIndicatorSize;
}
else if (_styleState.HasFlag(ControlStyleState.Off))
{
IndicatorCheckedMarkEffectSize = CheckIndicatorSize * 0.7;
}
else if (_styleState.HasFlag(ControlStyleState.Indeterminate))
{
IndicatorCheckedMarkEffectSize = CheckIndicatorSize * 0.7;
}
}
else
{
if (_styleState.HasFlag(ControlStyleState.On)) IndicatorCheckedMarkEffectSize = CheckIndicatorSize;
if (_styleState.HasFlag(ControlStyleState.On))
{
IndicatorCheckedMarkEffectSize = CheckIndicatorSize;
}
}
}
@ -295,15 +308,17 @@ public class CheckBox : AvaloniaCheckBox,
void IControlCustomStyle.HandlePropertyChangedForStyle(AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == IsPointerOverProperty ||
e.Property == IsCheckedProperty ||
e.Property == IsCheckedProperty ||
e.Property == IsEnabledProperty)
{
_customStyle.CollectStyleState();
SetupIndicatorCheckedMarkEffectSize();
if (e.Property == IsCheckedProperty &&
if (e.Property == IsCheckedProperty &&
_styleState.HasFlag(ControlStyleState.Enabled) &&
_styleState.HasFlag(ControlStyleState.On))
{
WaveSpiritAdorner.ShowWaveAdorner(this, WaveType.RoundRectWave);
}
}
}

View File

@ -13,7 +13,7 @@ internal class CheckBoxToken : AbstractControlDesignToken
}
/// <summary>
/// 复选框标志的大小
/// 复选框标志的大小
/// </summary>
public double CheckIndicatorSize { get; set; }

View File

@ -20,14 +20,12 @@ public enum CollapseTriggerType
Icon
}
public enum CollapseExpandIconPosition
{
Start,
End
}
[TemplatePart(CollapseTheme.ItemsPresenterPart, typeof(ItemsPresenter))]
public class Collapse : SelectingItemsControl
{
@ -50,9 +48,15 @@ public class Collapse : SelectingItemsControl
private void SetupItemsBorderThickness()
{
if (VisualRoot is not null)
{
for (var i = 0; i < ItemCount; ++i)
{
if (Items[i] is CollapseItem collapseItem)
{
SetupCollapseBorderThickness(collapseItem, i);
}
}
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@ -100,17 +104,24 @@ public class Collapse : SelectingItemsControl
{
if (!IsBorderless)
{
if (index == ItemCount - 1 && !collapseItem.IsSelected) headerBorderBottom = 0d;
if (index == ItemCount - 1 && !collapseItem.IsSelected)
{
headerBorderBottom = 0d;
}
}
else
{
if (collapseItem.IsSelected || (index == ItemCount - 1 && !collapseItem.IsSelected))
{
headerBorderBottom = 0d;
}
}
if (index == ItemCount - 1 &&
(collapseItem.IsSelected || (!collapseItem.IsSelected && collapseItem.InAnimating)))
{
contentBorderBottom = 0d;
}
}
else
{
@ -130,8 +141,12 @@ public class Collapse : SelectingItemsControl
{
var containerFromEventSource = GetContainerFromEventSource(e.Source);
if (containerFromEventSource is CollapseItem collapseItem)
{
if (!collapseItem.InAnimating)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
}
}
@ -142,8 +157,12 @@ public class Collapse : SelectingItemsControl
{
var containerFromEventSource = GetContainerFromEventSource(e.Source);
if (containerFromEventSource is CollapseItem collapseItem)
{
if (!collapseItem.InAnimating && collapseItem.IsPointInHeaderBounds(e.GetPosition(collapseItem)))
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
}
}
@ -154,12 +173,16 @@ public class Collapse : SelectingItemsControl
var container = GetContainerFromEventSource(e.Source);
if (container != null
&& container.GetVisualsAt(e.GetPosition(container))
.Any(c => container == c || container.IsVisualAncestorOf(c)))
.Any(c => container == c || container.IsVisualAncestorOf(c)))
{
var containerFromEventSource = GetContainerFromEventSource(e.Source);
if (containerFromEventSource is CollapseItem collapseItem)
{
if (!collapseItem.InAnimating && collapseItem.IsPointInHeaderBounds(e.GetPosition(collapseItem)))
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
}
}
}
@ -168,34 +191,48 @@ public class Collapse : SelectingItemsControl
{
base.OnPropertyChanged(change);
if (VisualRoot is not null)
{
if (change.Property == IsBorderlessProperty)
{
SetupEffectiveBorderThickness();
}
}
if (change.Property == IsAccordionProperty)
{
SetupSelectionMode();
}
else if (change.Property == IsBorderlessProperty ||
change.Property == IsGhostStyleProperty)
{
SetupItemsBorderThickness();
}
}
private void SetupEffectiveBorderThickness()
{
if (IsBorderless || IsGhostStyle)
{
EffectiveBorderThickness = default;
}
else
{
EffectiveBorderThickness = BorderThickness;
}
}
private void SetupSelectionMode()
{
if (IsAccordion)
{
SelectionMode = SelectionMode.Single | SelectionMode.Toggle;
}
else
{
SelectionMode = SelectionMode.Multiple | SelectionMode.Toggle;
}
}
#region
public static readonly StyledProperty<SizeType> SizeTypeProperty =
@ -254,8 +291,6 @@ public class Collapse : SelectingItemsControl
#endregion
#region
internal static readonly DirectProperty<Collapse, Thickness> EffectiveBorderThicknessProperty =

View File

@ -43,16 +43,25 @@ public class CollapseItem : HeaderedContentControl, ISelectable
{
if (obj.NewValue is IHeadered headered)
{
if (Header != headered.Header) SetCurrentValue(HeaderProperty, headered.Header);
if (Header != headered.Header)
{
SetCurrentValue(HeaderProperty, headered.Header);
}
}
else
{
if (!(obj.NewValue is Control)) SetCurrentValue(HeaderProperty, obj.NewValue);
if (!(obj.NewValue is Control))
{
SetCurrentValue(HeaderProperty, obj.NewValue);
}
}
}
else
{
if (Header == obj.OldValue) SetCurrentValue(HeaderProperty, obj.NewValue);
if (Header == obj.OldValue)
{
SetCurrentValue(HeaderProperty, obj.NewValue);
}
}
}
@ -68,28 +77,47 @@ public class CollapseItem : HeaderedContentControl, ISelectable
HandleSelectedChanged();
_enableAnimation = true;
if (_expandButton is not null)
{
_expandButton.Click += (sender, args) => { IsSelected = !IsSelected; };
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ExpandIconProperty) SetupIconButton();
if (change.Property == ExpandIconProperty)
{
SetupIconButton();
}
if (VisualRoot is not null)
{
if (change.Property == IsSelectedProperty)
{
HandleSelectedChanged();
}
}
if (change.Property == AddOnContentProperty)
{
if (change.OldValue is Control oldControl) UIStructureUtils.SetTemplateParent(oldControl, null);
if (change.OldValue is Control oldControl)
{
UIStructureUtils.SetTemplateParent(oldControl, null);
}
if (change.NewValue is Control newControl) UIStructureUtils.SetTemplateParent(newControl, this);
if (change.NewValue is Control newControl)
{
UIStructureUtils.SetTemplateParent(newControl, this);
}
}
else if (change.Property == ExpandIconProperty)
{
var oldExpandIcon = change.GetOldValue<PathIcon?>();
if (oldExpandIcon is not null) UIStructureUtils.SetTemplateParent(oldExpandIcon, null);
if (oldExpandIcon is not null)
{
UIStructureUtils.SetTemplateParent(oldExpandIcon, null);
}
SetupIconButton();
}
}
@ -99,15 +127,22 @@ public class CollapseItem : HeaderedContentControl, ISelectable
if (Presenter is not null)
{
if (IsSelected)
{
ExpandItemContent();
}
else
{
CollapseItemContent();
}
}
}
private void ExpandItemContent()
{
if (_animationTarget is null || InAnimating) return;
if (_animationTarget is null || InAnimating)
{
return;
}
if (!_enableAnimation)
{
@ -135,7 +170,10 @@ public class CollapseItem : HeaderedContentControl, ISelectable
private void CollapseItemContent()
{
if (_animationTarget is null || InAnimating) return;
if (_animationTarget is null || InAnimating)
{
return;
}
if (!_enableAnimation)
{
@ -180,12 +218,13 @@ public class CollapseItem : HeaderedContentControl, ISelectable
internal bool IsPointInHeaderBounds(Point position)
{
if (_headerDecorator is not null && TriggerType != CollapseTriggerType.Icon)
{
return _headerDecorator.Bounds.Contains(position);
}
return false;
}
#region
public static readonly StyledProperty<bool> IsSelectedProperty =
@ -235,8 +274,6 @@ public class CollapseItem : HeaderedContentControl, ISelectable
#endregion
#region
internal static readonly DirectProperty<CollapseItem, SizeType> SizeTypeProperty =

View File

@ -257,9 +257,9 @@ internal class CollapseItemTheme : BaseControlTheme
private void BuildTriggerStyle()
{
var headerTriggerHandleStyle = new Style(selector => selector.Nesting()
.PropertyEquals(
CollapseItem.TriggerTypeProperty,
CollapseTriggerType.Header));
.PropertyEquals(
CollapseItem.TriggerTypeProperty,
CollapseTriggerType.Header));
var headerDecoratorStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart));
headerDecoratorStyle.Add(InputElement.CursorProperty, new Cursor(StandardCursorType.Hand));
headerTriggerHandleStyle.Add(headerDecoratorStyle);
@ -267,7 +267,7 @@ internal class CollapseItemTheme : BaseControlTheme
var iconTriggerHandleStyle =
new Style(selector => selector.Nesting()
.PropertyEquals(CollapseItem.TriggerTypeProperty, CollapseTriggerType.Icon));
.PropertyEquals(CollapseItem.TriggerTypeProperty, CollapseTriggerType.Icon));
var expandIconStyle = new Style(selector => selector.Nesting().Template().Name(ExpandButtonPart));
expandIconStyle.Add(InputElement.CursorProperty, new Cursor(StandardCursorType.Hand));
iconTriggerHandleStyle.Add(expandIconStyle);
@ -277,9 +277,9 @@ internal class CollapseItemTheme : BaseControlTheme
private void BuildTriggerPositionStyle()
{
var startPositionStyle = new Style(selector => selector.Nesting()
.PropertyEquals(
CollapseItem.ExpandIconPositionProperty,
CollapseExpandIconPosition.Start));
.PropertyEquals(
CollapseItem.ExpandIconPositionProperty,
CollapseExpandIconPosition.Start));
{
var expandButtonStyle = new Style(selector => selector.Nesting().Template().Name(ExpandButtonPart));
expandButtonStyle.Add(Grid.ColumnProperty, 0);
@ -288,9 +288,9 @@ internal class CollapseItemTheme : BaseControlTheme
}
Add(startPositionStyle);
var endPositionStyle = new Style(selector => selector.Nesting()
.PropertyEquals(
CollapseItem.ExpandIconPositionProperty,
CollapseExpandIconPosition.End));
.PropertyEquals(
CollapseItem.ExpandIconPositionProperty,
CollapseExpandIconPosition.End));
{
var expandButtonStyle = new Style(selector => selector.Nesting().Template().Name(ExpandButtonPart));
expandButtonStyle.Add(Grid.ColumnProperty, 3);
@ -326,7 +326,7 @@ internal class CollapseItemTheme : BaseControlTheme
new Style(selector => selector.Nesting().Class(StdPseudoClass.Disabled));
disabledStyle.Add(TemplatedControl.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
var headerContentPresenterStyle = new Style(selector => selector.Nesting().Template().Name(HeaderDecoratorPart)
.Descendant().OfType<ContentPresenter>());
.Descendant().OfType<ContentPresenter>());
headerContentPresenterStyle.Add(ContentPresenter.ForegroundProperty, GlobalTokenResourceKey.ColorTextDisabled);
disabledStyle.Add(headerContentPresenterStyle);
@ -336,7 +336,7 @@ internal class CollapseItemTheme : BaseControlTheme
private void BuildAddOnContentStyle()
{
var addOnContentStyle = new Style(selector => selector.Nesting().Template().Name(AddOnContentPresenterPart)
.Descendant().OfType<PathIcon>());
.Descendant().OfType<PathIcon>());
addOnContentStyle.Add(Layoutable.WidthProperty, GlobalTokenResourceKey.IconSize);
addOnContentStyle.Add(Layoutable.HeightProperty, GlobalTokenResourceKey.IconSize);
Add(addOnContentStyle);

View File

@ -15,22 +15,22 @@ internal class CollapseToken : AbstractControlDesignToken
}
/// <summary>
/// 折叠面板头部内边距
/// 折叠面板头部内边距
/// </summary>
public Thickness HeaderPadding { get; set; }
/// <summary>
/// 折叠面板头部背景
/// 折叠面板头部背景
/// </summary>
public Color HeaderBg { get; set; }
/// <summary>
/// 折叠面板内容内边距
/// 折叠面板内容内边距
/// </summary>
public Thickness ContentPadding { get; set; }
/// <summary>
/// 折叠面板内容背景
/// 折叠面板内容背景
/// </summary>
public Color ContentBg { get; set; }
@ -50,8 +50,6 @@ internal class CollapseToken : AbstractControlDesignToken
RightExpandButtonMargin = new Thickness(_globalToken.MarginSM, 0, 0, 0);
}
#region Token
public Thickness CollapseHeaderPaddingSM { get; set; }

Some files were not shown because too many files have changed in this diff Show More