-
Notifications
You must be signed in to change notification settings - Fork 703
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f3b0e46
commit e48de38
Showing
12 changed files
with
1,346 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
...crosoft/UI/Xaml/Controls/RadioButtons/ColumnMajorUniformToLargestGridLayout.Properties.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
using Windows.UI.Xaml; | ||
|
||
namespace Microsoft.UI.Xaml.Controls.Primitives | ||
{ | ||
public partial class ColumnMajorUniformToLargestGridLayout | ||
{ | ||
public double ColumnSpacing | ||
{ | ||
get => (double)GetValue(ColumnSpacingProperty); | ||
set => SetValue(ColumnSpacingProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty ColumnSpacingProperty = | ||
DependencyProperty.Register(nameof(ColumnSpacing), typeof(double), typeof(ColumnMajorUniformToLargestGridLayout), new PropertyMetadata(default(double), OnColumnSpacingPropertyChanged)); | ||
|
||
public int MaxColumns | ||
{ | ||
get => (int)GetValue(MaxColumnsProperty); | ||
set => SetValue(MaxColumnsProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty MaxColumnsProperty = | ||
DependencyProperty.Register(nameof(MaxColumns), typeof(int), typeof(ColumnMajorUniformToLargestGridLayout), new PropertyMetadata(default(int), OnMaxColumnsPropertyChanged)); | ||
|
||
public double RowSpacing | ||
{ | ||
get => (double)GetValue(RowSpacingProperty); | ||
set => SetValue(RowSpacingProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty RowSpacingProperty = | ||
DependencyProperty.Register(nameof(RowSpacing), typeof(double), typeof(ColumnMajorUniformToLargestGridLayout), new PropertyMetadata(default(double), OnRowSpacingPropertyChanged)); | ||
|
||
private static void OnColumnSpacingPropertyChanged( | ||
DependencyObject sender, | ||
DependencyPropertyChangedEventArgs args) | ||
{ | ||
var owner = (ColumnMajorUniformToLargestGridLayout)sender; | ||
owner.OnColumnSpacingPropertyChanged(args); | ||
} | ||
|
||
private static void OnMaxColumnsPropertyChanged( | ||
DependencyObject sender, | ||
DependencyPropertyChangedEventArgs args) | ||
{ | ||
var owner = (ColumnMajorUniformToLargestGridLayout)sender; | ||
|
||
var value = (int)args.NewValue; | ||
var coercedValue = value; | ||
owner.ValidateGreaterThanZero(coercedValue); | ||
if (value != coercedValue) | ||
{ | ||
sender.SetValue(args.Property, coercedValue); | ||
return; | ||
} | ||
|
||
owner.OnMaxColumnsPropertyChanged(args); | ||
} | ||
|
||
private static void OnRowSpacingPropertyChanged( | ||
DependencyObject sender, | ||
DependencyPropertyChangedEventArgs args) | ||
{ | ||
var owner = (ColumnMajorUniformToLargestGridLayout)sender; | ||
owner.OnRowSpacingPropertyChanged(args); | ||
} | ||
} | ||
} |
207 changes: 207 additions & 0 deletions
207
src/Uno.UI/Microsoft/UI/Xaml/Controls/RadioButtons/ColumnMajorUniformToLargestGridLayout.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
using System; | ||
using Windows.Foundation; | ||
using Windows.UI.Xaml; | ||
|
||
namespace Microsoft.UI.Xaml.Controls.Primitives | ||
{ | ||
public partial class ColumnMajorUniformToLargestGridLayout : NonVirtualizingLayout | ||
{ | ||
private int m_actualColumnCount = 1; | ||
private Size m_largestChildSize = Size.Empty; | ||
|
||
//Testhooks helpers, only function while m_testHooksEnabled == true | ||
private bool m_testHooksEnabled = false; | ||
|
||
private int m_rows = -1; | ||
|
||
private int m_columns = -1; | ||
|
||
private int m_largerColumns = -1; | ||
|
||
protected internal override Size MeasureOverride(NonVirtualizingLayoutContext context, Size availableSize) | ||
{ | ||
var children = context.Children; | ||
if (children != null) | ||
{ | ||
Size GetLargestChildSize() | ||
{ | ||
var largestChildWidth = 0.0; | ||
var largestChildHeight = 0.0; | ||
foreach (var child in children) | ||
{ | ||
child.Measure(availableSize); | ||
var desiredSize = child.DesiredSize; | ||
if (desiredSize.Width > largestChildWidth) | ||
{ | ||
largestChildWidth = desiredSize.Width; | ||
} | ||
if (desiredSize.Height > largestChildHeight) | ||
{ | ||
largestChildHeight = desiredSize.Height; | ||
} | ||
} | ||
return new Size(largestChildWidth, largestChildHeight); | ||
} | ||
|
||
m_largestChildSize = GetLargestChildSize(); | ||
|
||
m_actualColumnCount = CalculateColumns(children.Count, m_largestChildSize.Width, availableSize.Width); | ||
var maxItemsPerColumn = (int)(Math.Ceiling((double)(children.Count) / (double)(m_actualColumnCount))); | ||
return new Size( | ||
(m_largestChildSize.Width * m_actualColumnCount) + | ||
((float)(ColumnSpacing) * (m_actualColumnCount - 1)), | ||
(m_largestChildSize.Height * maxItemsPerColumn) + | ||
((float)(RowSpacing) * (maxItemsPerColumn - 1)) | ||
); | ||
} | ||
return new Size(0, 0); | ||
} | ||
|
||
protected internal override Size ArrangeOverride(NonVirtualizingLayoutContext context, Size finalSize) | ||
{ | ||
var children = context.Children; | ||
if (children != null) | ||
{ | ||
var itemCount = children.Count; | ||
var minitemsPerColumn = (int)(Math.Floor((float)(itemCount) / m_actualColumnCount)); | ||
var numberOfColumnsWithExtraElements = (int)(itemCount % (int)(m_actualColumnCount)); | ||
|
||
var columnSpacing = (float)(ColumnSpacing); | ||
var rowSpacing = (float)(RowSpacing); | ||
|
||
var horizontalOffset = 0.0; | ||
var verticalOffset = 0.0; | ||
var index = 0; | ||
var column = 0; | ||
foreach (var child in children) | ||
{ | ||
var desiredSize = child.DesiredSize; | ||
child.Arrange(new Rect(horizontalOffset, verticalOffset, desiredSize.Width, desiredSize.Height)); | ||
if (column < numberOfColumnsWithExtraElements) | ||
{ | ||
if (index % (minitemsPerColumn + 1) == minitemsPerColumn) | ||
{ | ||
horizontalOffset += m_largestChildSize.Width + columnSpacing; | ||
verticalOffset = 0.0; | ||
column++; | ||
} | ||
else | ||
{ | ||
verticalOffset += m_largestChildSize.Height + rowSpacing; | ||
} | ||
} | ||
else | ||
{ | ||
var indexAfterExtraLargeColumns = index - (numberOfColumnsWithExtraElements * (minitemsPerColumn + 1)); | ||
if (indexAfterExtraLargeColumns % minitemsPerColumn == minitemsPerColumn - 1) | ||
{ | ||
horizontalOffset += m_largestChildSize.Width + columnSpacing; | ||
verticalOffset = 0.0; | ||
column++; | ||
} | ||
else | ||
{ | ||
verticalOffset += m_largestChildSize.Height + rowSpacing; | ||
} | ||
} | ||
index++; | ||
} | ||
|
||
if (m_testHooksEnabled) | ||
{ | ||
//Testhooks setup | ||
if (m_largerColumns != numberOfColumnsWithExtraElements || | ||
m_columns != column || | ||
m_rows != minitemsPerColumn) | ||
{ | ||
m_largerColumns = numberOfColumnsWithExtraElements; | ||
m_columns = column; | ||
m_rows = minitemsPerColumn; | ||
|
||
LayoutChanged?.Invoke(this, null); | ||
} | ||
} | ||
} | ||
return finalSize; | ||
} | ||
|
||
void OnColumnSpacingPropertyChanged(DependencyPropertyChangedEventArgs args) | ||
{ | ||
InvalidateMeasure(); | ||
} | ||
|
||
void OnRowSpacingPropertyChanged(DependencyPropertyChangedEventArgs args) | ||
{ | ||
InvalidateMeasure(); | ||
} | ||
|
||
void OnMaxColumnsPropertyChanged(DependencyPropertyChangedEventArgs args) | ||
{ | ||
InvalidateMeasure(); | ||
} | ||
|
||
int CalculateColumns(int childCount, double maxItemWidth, double availableWidth) | ||
{ | ||
/* | ||
-------------------------------------------------------------- | ||
| |-----------|-----------| | widthNeededForExtraColumn | | ||
| | | | ||
| |------| |------| | ColumnSpacing | | ||
| |----| |----| |----| | maxItemWidth | | ||
| O RB O RB O RB | | | ||
-------------------------------------------------------------- | ||
*/ | ||
|
||
// Every column execpt the first takes this ammount of space to fit on screen. | ||
var widthNeededForExtraColumn = ColumnSpacing + maxItemWidth; | ||
// The number of columns from data and api ignoring available space | ||
var requestedColumnCount = Math.Min(MaxColumns, childCount); | ||
|
||
// If columns can be added with effectively 0 extra space return as many columns as needed. | ||
if (widthNeededForExtraColumn < float.Epsilon) | ||
{ | ||
return requestedColumnCount; | ||
} | ||
|
||
var extraWidthAfterFirstColumn = availableWidth - maxItemWidth; | ||
var maxExtraColumns = Math.Max(0.0, Math.Floor(extraWidthAfterFirstColumn / widthNeededForExtraColumn)); | ||
|
||
// The smaller of number of columns from data and api and | ||
// the number of columns the available space can support | ||
var effectiveColumnCount = Math.Min((double)(requestedColumnCount), maxExtraColumns + 1); | ||
// return 1 even if there isn't any data | ||
return Math.Max(1, (int)(effectiveColumnCount)); | ||
} | ||
|
||
private void ValidateGreaterThanZero(int value) | ||
{ | ||
if (value <= 0) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(value)); | ||
} | ||
} | ||
|
||
//Testhooks helpers, only function while m_testHooksEnabled == true | ||
internal void SetTestHooksEnabled(bool enabled) | ||
{ | ||
m_testHooksEnabled = enabled; | ||
} | ||
|
||
internal int GetRows() | ||
{ | ||
return m_rows; | ||
} | ||
|
||
internal int GetColumns() | ||
{ | ||
return m_columns; | ||
} | ||
|
||
internal int GetLargerColumns() | ||
{ | ||
return m_largerColumns; | ||
} | ||
|
||
internal event TypedEventHandler<ColumnMajorUniformToLargestGridLayout, object> LayoutChanged; | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/Uno.UI/Microsoft/UI/Xaml/Controls/RadioButtons/RadioButton.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. --> | ||
<ResourceDictionary | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> | ||
|
||
<Style TargetType="RadioButton" BasedOn="{StaticResource DefaultRadioButtonStyle}" /> | ||
|
||
</ResourceDictionary> |
36 changes: 36 additions & 0 deletions
36
src/Uno.UI/Microsoft/UI/Xaml/Controls/RadioButtons/RadioButtons.Header.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
namespace Microsoft.UI.Xaml.Controls | ||
{ | ||
public partial class RadioButtons | ||
{ | ||
// This is an object that RadioButtons intends to attach to its child RadioButton elements. | ||
// It contains the revokers for the events on RadioButton that RadioButttons listens to | ||
// in order to manage selection. Attaching the revokers to the object allows the parent | ||
// RadioButtons the ability to "Set it and forget it" since the lifetime of the RadioButton | ||
// and these event registrations are now intrically linked. | ||
// This is not needed in Uno, as we can directly unsubscribe the events | ||
//private class ChildHandlers | ||
//{ | ||
// ToggleButton Checked_revoker checkedRevoker; | ||
// winrt::ToggleButton::Unchecked_revoker uncheckedRevoker; | ||
//} | ||
|
||
private int m_selectedIndex = -1; | ||
|
||
// This is used to guard against reentrency when calling select, since select changes | ||
// the Selected Index/Item which in turn calls select. | ||
private bool m_currentlySelecting = false; | ||
|
||
// We block selection before the control has loaded. | ||
// This is to ensure that we do not overwrite a provided Selected Index/Item value. | ||
private bool m_blockSelecting = true; | ||
|
||
private ItemsRepeater m_repeater = null; | ||
|
||
private RadioButtonsElementFactory m_radioButtonsElementFactory = null; | ||
|
||
private bool m_testHooksEnabled = false; | ||
|
||
private const string s_repeaterName = "InnerRepeater"; | ||
private const string s_childHandlersPropertyName = "ChildHandlers"; | ||
} | ||
} |
Oops, something went wrong.