Browse Source

Merge branch 'master' into closing-event

pull/1383/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
6727d2f4a9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      samples/ControlCatalog/ControlCatalog.csproj
  2. 1
      samples/ControlCatalog/MainView.xaml
  3. 24
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
  4. 54
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  5. 258
      src/Avalonia.Controls/ButtonSpinner.cs
  6. 4
      src/Avalonia.Controls/Remote/RemoteWidget.cs
  7. 29
      src/Avalonia.Controls/RepeatButton.cs
  8. 174
      src/Avalonia.Controls/Spinner.cs
  9. 86
      src/Avalonia.Themes.Default/ButtonSpinner.xaml
  10. 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  11. 10
      src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs
  12. 6
      src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs
  13. 4
      src/Avalonia.Visuals/Platform/IWriteableBitmapImpl.cs
  14. 12
      src/OSX/Avalonia.MonoMac/TopLevelImpl.cs
  15. 2
      src/Skia/Avalonia.Skia/BitmapImpl.cs
  16. 2
      src/Skia/Avalonia.Skia/PlatformRenderInterface.cs
  17. 4
      src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs
  18. 4
      src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs
  19. 10
      tests/Avalonia.RenderTests/Media/BitmapTests.cs
  20. 2
      tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs
  21. 2
      tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs
  22. 0
      tests/TestFiles/Direct2D1/Media/Bitmap/WriteableBitmapShouldBeUsable_Bgra8888.expected.png
  23. 0
      tests/TestFiles/Direct2D1/Media/Bitmap/WriteableBitmapShouldBeUsable_Rgba8888.expected.png
  24. 0
      tests/TestFiles/Skia/Media/Bitmap/WriteableBitmapShouldBeUsable_Bgra8888.expected.png
  25. 0
      tests/TestFiles/Skia/Media/Bitmap/WriteableBitmapShouldBeUsable_Rgba8888.expected.png

6
samples/ControlCatalog/ControlCatalog.csproj

@ -35,6 +35,9 @@
<EmbeddedResource Include="DecoratedWindow.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\ButtonSpinnerPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\DialogsPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
@ -164,6 +167,9 @@
<Compile Include="Pages\ToolTipPage.xaml.cs">
<DependentUpon>ToolTipPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\ButtonSpinnerPage.xaml.cs">
<DependentUpon>ButtonSpinnerPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\ScreenPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>

1
samples/ControlCatalog/MainView.xaml

@ -7,6 +7,7 @@
</TabControl.Transition>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="ButtonSpinner"><pages:ButtonSpinnerPage/></TabItem>
<TabItem Header="Calendar"><pages:CalendarPage/></TabItem>
<TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
<TabItem Header="Carousel"><pages:CarouselPage/></TabItem>

24
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml

@ -0,0 +1,24 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Vertical" Gap="4">
<TextBlock Classes="h1">ButtonSpinner</TextBlock>
<TextBlock Classes="h2">The ButtonSpinner control allows you to add button spinners to any element and then respond to the Spin event to manipulate that element.</TextBlock>
<StackPanel Orientation="Vertical" Gap="8" Width="200" Margin="0,20,0,0">
<CheckBox Name="allowSpinCheck" IsChecked="True">AllowSpin</CheckBox>
<CheckBox Name="showSpinCheck" IsChecked="True">ShowButtonSpinner</CheckBox>
<ButtonSpinner Spin="OnSpin" Height="30"
AllowSpin="{Binding #allowSpinCheck.IsChecked}"
ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
</ButtonSpinner>
<ButtonSpinner Spin="OnSpin" Height="30" ButtonSpinnerLocation="Left"
AllowSpin="{Binding #allowSpinCheck.IsChecked}"
ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
</ButtonSpinner>
</StackPanel>
</StackPanel>
</UserControl>

54
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@ -0,0 +1,54 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
namespace ControlCatalog.Pages
{
public class ButtonSpinnerPage : UserControl
{
public ButtonSpinnerPage()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void OnSpin(object sender, SpinEventArgs e)
{
var spinner = (ButtonSpinner)sender;
var txtBox = (TextBlock)spinner.Content;
int value = Array.IndexOf(_mountains, txtBox.Text);
if (e.Direction == SpinDirection.Increase)
value++;
else
value--;
if (value < 0)
value = _mountains.Length - 1;
else if (value >= _mountains.Length)
value = 0;
txtBox.Text = _mountains[value];
}
private readonly string[] _mountains = new[]
{
"Everest",
"K2 (Mount Godwin Austen)",
"Kangchenjunga",
"Lhotse",
"Makalu",
"Cho Oyu",
"Dhaulagiri",
"Manaslu",
"Nanga Parbat",
"Annapurna"
};
}
}

258
src/Avalonia.Controls/ButtonSpinner.cs

@ -0,0 +1,258 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Controls
{
public enum Location
{
Left,
Right
}
/// <summary>
/// Represents a spinner control that includes two Buttons.
/// </summary>
public class ButtonSpinner : Spinner
{
/// <summary>
/// Defines the <see cref="AllowSpin"/> property.
/// </summary>
public static readonly StyledProperty<bool> AllowSpinProperty =
AvaloniaProperty.Register<ButtonSpinner, bool>(nameof(AllowSpin), true);
/// <summary>
/// Defines the <see cref="ShowButtonSpinner"/> property.
/// </summary>
public static readonly StyledProperty<bool> ShowButtonSpinnerProperty =
AvaloniaProperty.Register<ButtonSpinner, bool>(nameof(ShowButtonSpinner), true);
/// <summary>
/// Defines the <see cref="ButtonSpinnerLocation"/> property.
/// </summary>
public static readonly StyledProperty<Location> ButtonSpinnerLocationProperty =
AvaloniaProperty.Register<ButtonSpinner, Location>(nameof(ButtonSpinnerLocation), Location.Right);
private Button _decreaseButton;
/// <summary>
/// Gets or sets the DecreaseButton template part.
/// </summary>
private Button DecreaseButton
{
get { return _decreaseButton; }
set
{
if (_decreaseButton != null)
{
_decreaseButton.Click -= OnButtonClick;
}
_decreaseButton = value;
if (_decreaseButton != null)
{
_decreaseButton.Click += OnButtonClick;
}
}
}
private Button _increaseButton;
/// <summary>
/// Gets or sets the IncreaseButton template part.
/// </summary>
private Button IncreaseButton
{
get
{
return _increaseButton;
}
set
{
if (_increaseButton != null)
{
_increaseButton.Click -= OnButtonClick;
}
_increaseButton = value;
if (_increaseButton != null)
{
_increaseButton.Click += OnButtonClick;
}
}
}
/// <summary>
/// Initializes static members of the <see cref="ButtonSpinner"/> class.
/// </summary>
static ButtonSpinner()
{
AllowSpinProperty.Changed.Subscribe(AllowSpinChanged);
PseudoClass(ButtonSpinnerLocationProperty, location => location == Location.Left, ":left");
PseudoClass(ButtonSpinnerLocationProperty, location => location == Location.Right, ":right");
}
/// <summary>
/// Gets or sets a value indicating whether the <see cref="ButtonSpinner"/> should allow to spin.
/// </summary>
public bool AllowSpin
{
get { return GetValue(AllowSpinProperty); }
set { SetValue(AllowSpinProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether the spin buttons should be shown.
/// </summary>
public bool ShowButtonSpinner
{
get { return GetValue(ShowButtonSpinnerProperty); }
set { SetValue(ShowButtonSpinnerProperty, value); }
}
/// <summary>
/// Gets or sets current location of the <see cref="ButtonSpinner"/>.
/// </summary>
public Location ButtonSpinnerLocation
{
get { return GetValue(ButtonSpinnerLocationProperty); }
set { SetValue(ButtonSpinnerLocationProperty, value); }
}
/// <inheritdoc />
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
IncreaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
DecreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
SetButtonUsage();
}
/// <inheritdoc />
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
Point mousePosition;
if (IncreaseButton != null && IncreaseButton.IsEnabled == false)
{
mousePosition = e.GetPosition(IncreaseButton);
if (mousePosition.X > 0 && mousePosition.X < IncreaseButton.Width &&
mousePosition.Y > 0 && mousePosition.Y < IncreaseButton.Height)
{
e.Handled = true;
}
}
if (DecreaseButton != null && DecreaseButton.IsEnabled == false)
{
mousePosition = e.GetPosition(DecreaseButton);
if (mousePosition.X > 0 && mousePosition.X < DecreaseButton.Width &&
mousePosition.Y > 0 && mousePosition.Y < DecreaseButton.Height)
{
e.Handled = true;
}
}
}
/// <inheritdoc />
protected override void OnKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
if (AllowSpin)
{
OnSpin(new SpinEventArgs(SpinEvent, SpinDirection.Increase));
e.Handled = true;
}
break;
}
case Key.Down:
{
if (AllowSpin)
{
OnSpin(new SpinEventArgs(SpinEvent, SpinDirection.Decrease));
e.Handled = true;
}
break;
}
case Key.Enter:
{
//Do not Spin on enter Key when spinners have focus
if (((IncreaseButton != null) && (IncreaseButton.IsFocused))
|| ((DecreaseButton != null) && DecreaseButton.IsFocused))
{
e.Handled = true;
}
break;
}
}
}
/// <inheritdoc />
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
base.OnPointerWheelChanged(e);
if (!e.Handled && AllowSpin)
{
if (e.Delta.Y != 0)
{
var spinnerEventArgs = new SpinEventArgs(SpinEvent, (e.Delta.Y < 0) ? SpinDirection.Decrease : SpinDirection.Increase, true);
OnSpin(spinnerEventArgs);
e.Handled = spinnerEventArgs.Handled;
}
}
}
/// <summary>
/// Called when the <see cref="AllowSpin"/> property value changed.
/// </summary>
/// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param>
protected virtual void OnAllowSpinChanged(bool oldValue, bool newValue)
{
SetButtonUsage();
}
/// <summary>
/// Called when the <see cref="AllowSpin"/> property value changed.
/// </summary>
/// <param name="e">The event args.</param>
private static void AllowSpinChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.Sender is ButtonSpinner spinner)
{
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
spinner.OnAllowSpinChanged(oldValue, newValue);
}
}
/// <summary>
/// Disables or enables the buttons based on the valid spin direction.
/// </summary>
private void SetButtonUsage()
{
if (IncreaseButton != null)
{
IncreaseButton.IsEnabled = AllowSpin && ((ValidSpinDirection & ValidSpinDirections.Increase) == ValidSpinDirections.Increase);
}
if (DecreaseButton != null)
{
DecreaseButton.IsEnabled = AllowSpin && ((ValidSpinDirection & ValidSpinDirections.Decrease) == ValidSpinDirections.Decrease);
}
}
/// <summary>
/// Called when user clicks one of the spin buttons.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (AllowSpin)
{
var direction = sender == IncreaseButton ? SpinDirection.Increase : SpinDirection.Decrease;
OnSpin(new SpinEventArgs(SpinEvent, direction));
}
}
}
}

4
src/Avalonia.Controls/Remote/RemoteWidget.cs

@ -14,7 +14,7 @@ namespace Avalonia.Controls.Remote
{
private readonly IAvaloniaRemoteTransportConnection _connection;
private FrameMessage _lastFrame;
private WritableBitmap _bitmap;
private WriteableBitmap _bitmap;
public RemoteWidget(IAvaloniaRemoteTransportConnection connection)
{
_connection = connection;
@ -62,7 +62,7 @@ namespace Avalonia.Controls.Remote
var fmt = (PixelFormat) _lastFrame.Format;
if (_bitmap == null || _bitmap.PixelWidth != _lastFrame.Width ||
_bitmap.PixelHeight != _lastFrame.Height)
_bitmap = new WritableBitmap(_lastFrame.Width, _lastFrame.Height, fmt);
_bitmap = new WriteableBitmap(_lastFrame.Width, _lastFrame.Height, fmt);
using (var l = _bitmap.Lock())
{
var lineLen = (fmt == PixelFormat.Rgb565 ? 2 : 4) * _lastFrame.Width;

29
src/Avalonia.Controls/RepeatButton.cs

@ -6,17 +6,32 @@ namespace Avalonia.Controls
{
public class RepeatButton : Button
{
/// <summary>
/// Defines the <see cref="Interval"/> property.
/// </summary>
public static readonly StyledProperty<int> IntervalProperty =
AvaloniaProperty.Register<Button, int>(nameof(Interval), 100);
/// <summary>
/// Defines the <see cref="Delay"/> property.
/// </summary>
public static readonly StyledProperty<int> DelayProperty =
AvaloniaProperty.Register<Button, int>(nameof(Delay), 100);
AvaloniaProperty.Register<Button, int>(nameof(Delay), 300);
private DispatcherTimer _repeatTimer;
/// <summary>
/// Gets or sets the amount of time, in milliseconds, of repeating clicks.
/// </summary>
public int Interval
{
get { return GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}
/// <summary>
/// Gets or sets the amount of time, in milliseconds, to wait before repeating begins.
/// </summary>
public int Delay
{
get { return GetValue(DelayProperty); }
@ -28,7 +43,7 @@ namespace Avalonia.Controls
if (_repeatTimer == null)
{
_repeatTimer = new DispatcherTimer();
_repeatTimer.Tick += (o, e) => OnClick();
_repeatTimer.Tick += RepeatTimerOnTick;
}
if (_repeatTimer.IsEnabled) return;
@ -37,6 +52,16 @@ namespace Avalonia.Controls
_repeatTimer.Start();
}
private void RepeatTimerOnTick(object sender, EventArgs e)
{
var interval = TimeSpan.FromMilliseconds(Interval);
if (_repeatTimer.Interval != interval)
{
_repeatTimer.Interval = interval;
}
OnClick();
}
private void StopTimer()
{
_repeatTimer?.Stop();

174
src/Avalonia.Controls/Spinner.cs

@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Interactivity;
namespace Avalonia.Controls
{
/// <summary>
/// Represents spin directions that are valid.
/// </summary>
[Flags]
public enum ValidSpinDirections
{
/// <summary>
/// Can not increase nor decrease.
/// </summary>
None = 0,
/// <summary>
/// Can increase.
/// </summary>
Increase = 1,
/// <summary>
/// Can decrease.
/// </summary>
Decrease = 2
}
/// <summary>
/// Represents spin directions that could be initiated by the end-user.
/// </summary>
public enum SpinDirection
{
/// <summary>
/// Represents a spin initiated by the end-user in order to Increase a value.
/// </summary>
Increase = 0,
/// <summary>
/// Represents a spin initiated by the end-user in order to Decrease a value.
/// </summary>
Decrease = 1
}
/// <summary>
/// Provides data for the Spinner.Spin event.
/// </summary>
public class SpinEventArgs : RoutedEventArgs
{
/// <summary>
/// Gets the SpinDirection for the spin that has been initiated by the end-user.
/// </summary>
public SpinDirection Direction { get; }
/// <summary>
/// Get or set whheter the spin event originated from a mouse wheel event.
/// </summary>
public bool UsingMouseWheel{ get; }
/// <summary>
/// Initializes a new instance of the SpinEventArgs class.
/// </summary>
/// <param name="direction">Spin direction.</param>
public SpinEventArgs(SpinDirection direction)
{
Direction = direction;
}
public SpinEventArgs(RoutedEvent routedEvent, SpinDirection direction)
: base(routedEvent)
{
Direction = direction;
}
public SpinEventArgs(SpinDirection direction, bool usingMouseWheel)
{
Direction = direction;
UsingMouseWheel = usingMouseWheel;
}
public SpinEventArgs(RoutedEvent routedEvent, SpinDirection direction, bool usingMouseWheel)
: base(routedEvent)
{
Direction = direction;
UsingMouseWheel = usingMouseWheel;
}
}
/// <summary>
/// Base class for controls that represents controls that can spin.
/// </summary>
public abstract class Spinner : ContentControl
{
/// <summary>
/// Defines the <see cref="ValidSpinDirection"/> property.
/// </summary>
public static readonly StyledProperty<ValidSpinDirections> ValidSpinDirectionProperty =
AvaloniaProperty.Register<Spinner, ValidSpinDirections>(nameof(ValidSpinDirection),
ValidSpinDirections.Increase | ValidSpinDirections.Decrease);
/// <summary>
/// Defines the <see cref="Spin"/> event.
/// </summary>
public static readonly RoutedEvent<SpinEventArgs> SpinEvent =
RoutedEvent.Register<Spinner, SpinEventArgs>(nameof(Spin), RoutingStrategies.Bubble);
/// <summary>
/// Initializes static members of the <see cref="Spinner"/> class.
/// </summary>
static Spinner()
{
ValidSpinDirectionProperty.Changed.Subscribe(OnValidSpinDirectionPropertyChanged);
}
/// <summary>
/// Occurs when spinning is initiated by the end-user.
/// </summary>
public event EventHandler<SpinEventArgs> Spin
{
add { AddHandler(SpinEvent, value); }
remove { RemoveHandler(SpinEvent, value); }
}
/// <summary>
/// Gets or sets <see cref="ValidSpinDirections"/> allowed for this control.
/// </summary>
public ValidSpinDirections ValidSpinDirection
{
get { return GetValue(ValidSpinDirectionProperty); }
set { SetValue(ValidSpinDirectionProperty, value); }
}
/// <summary>
/// Called when valid spin direction changed.
/// </summary>
/// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param>
protected virtual void OnValidSpinDirectionChanged(ValidSpinDirections oldValue, ValidSpinDirections newValue)
{
}
/// <summary>
/// Raises the OnSpin event when spinning is initiated by the end-user.
/// </summary>
/// <param name="e">Spin event args.</param>
protected virtual void OnSpin(SpinEventArgs e)
{
var valid = e.Direction == SpinDirection.Increase
? ValidSpinDirections.Increase
: ValidSpinDirections.Decrease;
//Only raise the event if spin is allowed.
if ((ValidSpinDirection & valid) == valid)
{
RaiseEvent(e);
}
}
/// <summary>
/// Called when the <see cref="ValidSpinDirection"/> property value changed.
/// </summary>
/// <param name="e">The event args.</param>
private static void OnValidSpinDirectionPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.Sender is Spinner spinner)
{
var oldValue = (ValidSpinDirections)e.OldValue;
var newValue = (ValidSpinDirections)e.NewValue;
spinner.OnValidSpinDirectionChanged(oldValue, newValue);
}
}
}
}

86
src/Avalonia.Themes.Default/ButtonSpinner.xaml

@ -0,0 +1,86 @@
<Styles xmlns="https://github.com/avaloniaui">
<Style Selector="ButtonSpinner">
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLightBrush}"/>
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style Selector="ButtonSpinner /template/ RepeatButton">
<Setter Property="RepeatButton.Background" Value="Transparent"/>
<Setter Property="RepeatButton.BorderBrush" Value="Transparent"/>
</Style>
<Style Selector="ButtonSpinner /template/ RepeatButton:pointerover">
<Setter Property="RepeatButton.Background" Value="{DynamicResource ThemeControlMidBrush}"/>
<Setter Property="RepeatButton.BorderBrush" Value="{DynamicResource ThemeBorderMidBrush}"/>
</Style>
<Style Selector="ButtonSpinner /template/ RepeatButton#PART_IncreaseButton">
<Setter Property="Content">
<Template>
<Path Fill="{DynamicResource ThemeForegroundBrush}"
Width="8"
Height="4"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,5 L4.5,.5 9,5 6,5 4.5,3.5 3,5 z"/>
</Template>
</Setter>
</Style>
<Style Selector="ButtonSpinner /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Content">
<Template>
<Path Fill="{DynamicResource ThemeForegroundBrush}"
Width="8"
Height="4"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M0,0 L3,0 4.5,1.5 6,0 9,0 4.5,4.5 z"/>
</Template>
</Setter>
</Style>
<Style Selector="ButtonSpinner:right">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid ColumnDefinitions="*,Auto">
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="0"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
<Grid Grid.Column="1" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
<RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ButtonSpinner:left">
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid ColumnDefinitions="Auto,*">
<Grid Grid.Column="0" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
<RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/>
</Grid>
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="1"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter>
</Style>
</Styles>

1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -42,4 +42,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.CalendarItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Calendar.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.DatePicker.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ButtonSpinner.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

10
src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs → src/Avalonia.Visuals/Media/Imaging/WriteableBitmap.cs

@ -9,15 +9,15 @@ using Avalonia.Utilities;
namespace Avalonia.Media.Imaging
{
/// <summary>
/// Holds a writable bitmap image.
/// Holds a writeable bitmap image.
/// </summary>
public class WritableBitmap : Bitmap
public class WriteableBitmap : Bitmap
{
public WritableBitmap(int width, int height, PixelFormat? format = null)
: base(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().CreateWritableBitmap(width, height, format))
public WriteableBitmap(int width, int height, PixelFormat? format = null)
: base(AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().CreateWriteableBitmap(width, height, format))
{
}
public ILockedFramebuffer Lock() => ((IWritableBitmapImpl) PlatformImpl.Item).Lock();
public ILockedFramebuffer Lock() => ((IWriteableBitmapImpl) PlatformImpl.Item).Lock();
}
}

6
src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs

@ -61,13 +61,13 @@ namespace Avalonia.Platform
double dpiY);
/// <summary>
/// Creates a writable bitmap implementation.
/// Creates a writeable bitmap implementation.
/// </summary>
/// <param name="width">The width of the bitmap.</param>
/// <param name="height">The height of the bitmap.</param>
/// <param name="format">Pixel format (optional).</param>
/// <returns>An <see cref="IWritableBitmapImpl"/>.</returns>
IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null);
/// <returns>An <see cref="IWriteableBitmapImpl"/>.</returns>
IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null);
/// <summary>
/// Loads a bitmap implementation from a file..

4
src/Avalonia.Visuals/Platform/IWritableBitmapImpl.cs → src/Avalonia.Visuals/Platform/IWriteableBitmapImpl.cs

@ -7,9 +7,9 @@ using System.Threading.Tasks;
namespace Avalonia.Platform
{
/// <summary>
/// Defines the platform-specific interface for a <see cref="Avalonia.Media.Imaging.WritableBitmap"/>.
/// Defines the platform-specific interface for a <see cref="Avalonia.Media.Imaging.WriteableBitmap"/>.
/// </summary>
public interface IWritableBitmapImpl : IBitmapImpl
public interface IWriteableBitmapImpl : IBitmapImpl
{
ILockedFramebuffer Lock();
}

12
src/OSX/Avalonia.MonoMac/TopLevelImpl.cs

@ -39,6 +39,7 @@ namespace Avalonia.MonoMac
private NSTrackingArea _area;
private NSCursor _cursor;
private bool _nonUiRedrawQueued;
private bool _isMouseOver;
public CGSize PixelSize { get; set; }
@ -133,7 +134,11 @@ namespace Avalonia.MonoMac
{
ResetCursorRects();
if (_cursor != null)
{
AddCursorRect(Frame, _cursor);
if (_isMouseOver)
_cursor.Set();
}
}
static readonly NSCursor ArrowCursor = NSCursor.ArrowCursor;
@ -299,10 +304,17 @@ namespace Avalonia.MonoMac
public override void MouseExited(NSEvent theEvent)
{
_isMouseOver = false;
MouseEvent(theEvent, RawMouseEventType.LeaveWindow);
base.MouseExited(theEvent);
}
public override void MouseEntered(NSEvent theEvent)
{
_isMouseOver = true;
base.MouseEntered(theEvent);
}
void KeyboardEvent(RawKeyEventType type, NSEvent ev)
{
var code = KeyTransform.TransformKeyCode(ev.KeyCode);

2
src/Skia/Avalonia.Skia/BitmapImpl.cs

@ -6,7 +6,7 @@ using SkiaSharp;
namespace Avalonia.Skia
{
class BitmapImpl : IRenderTargetBitmapImpl, IWritableBitmapImpl
class BitmapImpl : IRenderTargetBitmapImpl, IWriteableBitmapImpl
{
private Vector _dpi;

2
src/Skia/Avalonia.Skia/PlatformRenderInterface.cs

@ -88,7 +88,7 @@ namespace Avalonia.Skia
return new FramebufferRenderTarget(fb);
}
public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null)
{
return new BitmapImpl(width, height, new Vector(96, 96), format);
}

4
src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs

@ -168,9 +168,9 @@ namespace Avalonia.Direct2D1
dpiY);
}
public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null)
public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = null)
{
return new WritableWicBitmapImpl(s_imagingFactory, width, height, format);
return new WriteableWicBitmapImpl(s_imagingFactory, width, height, format);
}
public IStreamGeometryImpl CreateStreamGeometry()

4
src/Windows/Avalonia.Direct2D1/Media/Imaging/WritableWicBitmapImpl.cs → src/Windows/Avalonia.Direct2D1/Media/Imaging/WriteableWicBitmapImpl.cs

@ -9,9 +9,9 @@ using PixelFormat = Avalonia.Platform.PixelFormat;
namespace Avalonia.Direct2D1.Media.Imaging
{
class WritableWicBitmapImpl : WicBitmapImpl, IWritableBitmapImpl
class WriteableWicBitmapImpl : WicBitmapImpl, IWriteableBitmapImpl
{
public WritableWicBitmapImpl(ImagingFactory factory, int width, int height, PixelFormat? pixelFormat)
public WriteableWicBitmapImpl(ImagingFactory factory, int width, int height, PixelFormat? pixelFormat)
: base(factory, width, height, pixelFormat)
{
}

10
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@ -106,9 +106,9 @@ namespace Avalonia.Direct2D1.RenderTests.Media
[Theory]
[InlineData(PixelFormat.Bgra8888), InlineData(PixelFormat.Rgba8888)]
public void WritableBitmapShouldBeUsable(PixelFormat fmt)
public void WriteableBitmapShouldBeUsable(PixelFormat fmt)
{
var writableBitmap = new WritableBitmap(256, 256, fmt);
var writeableBitmap = new WriteableBitmap(256, 256, fmt);
var data = new int[256 * 256];
for (int y = 0; y < 256; y++)
@ -116,7 +116,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
data[y * 256 + x] =(int)((uint)(x + (y << 8)) | 0xFF000000u);
using (var l = writableBitmap.Lock())
using (var l = writeableBitmap.Lock())
{
for(var r = 0; r<256; r++)
{
@ -125,9 +125,9 @@ namespace Avalonia.Direct2D1.RenderTests.Media
}
var name = nameof(WritableBitmapShouldBeUsable) + "_" + fmt;
var name = nameof(WriteableBitmapShouldBeUsable) + "_" + fmt;
writableBitmap.Save(System.IO.Path.Combine(OutputPath, name + ".out.png"));
writeableBitmap.Save(System.IO.Path.Combine(OutputPath, name + ".out.png"));
CompareImagesNoRenderer(name);
}

2
tests/Avalonia.UnitTests/MockPlatformRenderInterface.cs

@ -39,7 +39,7 @@ namespace Avalonia.UnitTests
return new MockStreamGeometryImpl();
}
public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = default(PixelFormat?))
public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? format = default(PixelFormat?))
{
throw new NotImplementedException();
}

2
tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs

@ -49,7 +49,7 @@ namespace Avalonia.Visuals.UnitTests.VisualTree
throw new NotImplementedException();
}
public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? fmt)
public IWriteableBitmapImpl CreateWriteableBitmap(int width, int height, PixelFormat? fmt)
{
throw new NotImplementedException();
}

0
tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png → tests/TestFiles/Direct2D1/Media/Bitmap/WriteableBitmapShouldBeUsable_Bgra8888.expected.png

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

0
tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Rgba8888.expected.png → tests/TestFiles/Direct2D1/Media/Bitmap/WriteableBitmapShouldBeUsable_Rgba8888.expected.png

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

0
tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png → tests/TestFiles/Skia/Media/Bitmap/WriteableBitmapShouldBeUsable_Bgra8888.expected.png

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 144 KiB

0
tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Rgba8888.expected.png → tests/TestFiles/Skia/Media/Bitmap/WriteableBitmapShouldBeUsable_Rgba8888.expected.png

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Loading…
Cancel
Save