Browse Source

Merge branch 'master' into feature/xdg-desktop-portal-file-chooser

pull/8217/head
affederaffe 4 years ago
committed by GitHub
parent
commit
90a81a9548
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      native/Avalonia.Native/src/OSX/AvnPanelWindow.mm
  2. 4
      native/Avalonia.Native/src/OSX/AvnView.mm
  3. 81
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  4. 2
      native/Avalonia.Native/src/OSX/INSWindowHolder.h
  5. 6
      native/Avalonia.Native/src/OSX/WindowBaseImpl.h
  6. 19
      native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
  7. 8
      native/Avalonia.Native/src/OSX/WindowImpl.h
  8. 112
      native/Avalonia.Native/src/OSX/WindowImpl.mm
  9. 1
      native/Avalonia.Native/src/OSX/WindowProtocol.h
  10. 2
      samples/ControlCatalog/Pages/DialogsPage.xaml
  11. 13
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  12. 9
      src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
  13. 4
      src/Avalonia.Base/Styling/Style.cs
  14. 5
      src/Avalonia.Controls/ContextMenu.cs
  15. 5
      src/Avalonia.Controls/Flyouts/FlyoutBase.cs
  16. 74
      src/Avalonia.Themes.Fluent/Controls/Button.xaml
  17. 464
      src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml
  18. 5
      src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
  19. 34
      src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs
  20. 15
      src/Web/Avalonia.Web.Blazor/WinStubs.cs
  21. 2
      src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs
  22. 21
      tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
  23. 47
      tests/Avalonia.Controls.UnitTests/FlyoutTests.cs
  24. 32
      tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs
  25. 8
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

2
native/Avalonia.Native/src/OSX/AvnPanelWindow.mm

@ -3,8 +3,6 @@
// Copyright (c) 2022 Avalonia. All rights reserved.
//
#pragma once
#define IS_NSPANEL
#include "AvnWindow.mm"

4
native/Avalonia.Native/src/OSX/AvnView.mm

@ -222,7 +222,7 @@
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
{
bool triggerInputWhenDisabled = type != Move;
bool triggerInputWhenDisabled = type != Move && type != LeaveWindow;
if([self ignoreUserInput: triggerInputWhenDisabled])
{
@ -709,4 +709,4 @@
return [[self accessibilityChild] accessibilityFocusedUIElement];
}
@end
@end

81
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -68,7 +68,7 @@
}
}
- (void)performClose:(id)sender
- (void)performClose:(id _Nullable )sender
{
if([[self delegate] respondsToSelector:@selector(windowShouldClose:)])
{
@ -147,7 +147,7 @@
}
}
-(void) applyMenu:(AvnMenu *)menu
-(void) applyMenu:(AvnMenu *_Nullable)menu
{
if(menu == nullptr)
{
@ -157,7 +157,7 @@
_menu = menu;
}
-(CLASS_NAME*) initWithParent: (WindowBaseImpl*) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask;
-(CLASS_NAME*_Nonnull) initWithParent: (WindowBaseImpl*_Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask;
{
// https://jameshfisher.com/2020/07/10/why-is-the-contentrect-of-my-nswindow-ignored/
// create nswindow with specific contentRect, otherwise we wont be able to resize the window
@ -176,14 +176,15 @@
_isExtended = false;
#ifdef IS_NSPANEL
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorFullScreenAuxiliary];
#endif
if(self.isDialog)
{
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorFullScreenAuxiliary];
}
return self;
}
- (BOOL)windowShouldClose:(NSWindow *)sender
- (BOOL)windowShouldClose:(NSWindow *_Nonnull)sender
{
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw());
@ -195,21 +196,28 @@
return true;
}
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
- (void)windowDidChangeBackingProperties:(NSNotification *_Nonnull)notification
{
[self backingScaleFactor];
}
- (void)windowWillClose:(NSNotification *)notification
- (void)windowWillClose:(NSNotification *_Nonnull)notification
{
_closed = true;
if(_parent)
{
ComPtr<WindowBaseImpl> parent = _parent;
_parent = NULL;
[self restoreParentWindow];
auto window = dynamic_cast<WindowImpl*>(parent.getRaw());
if(window != nullptr)
{
window->SetParent(nullptr);
}
parent->BaseEvents->Closed();
[parent->View onClosed];
}
@ -220,17 +228,11 @@
if(_canBecomeKeyWindow)
{
// If the window has a child window being shown as a dialog then don't allow it to become the key window.
for(NSWindow* uch in [self childWindows])
auto parent = dynamic_cast<WindowImpl*>(_parent.getRaw());
if(parent != nullptr)
{
if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)])
{
continue;
}
id <AvnWindowProtocol> ch = (id <AvnWindowProtocol>) uch;
if(ch.isDialog)
return false;
return parent->CanBecomeKeyWindow();
}
return true;
@ -259,6 +261,10 @@
-(void) setEnabled:(bool)enable
{
_isEnabled = enable;
[[self standardWindowButton:NSWindowCloseButton] setEnabled:enable];
[[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:enable];
[[self standardWindowButton:NSWindowZoomButton] setEnabled:enable];
}
-(void)becomeKeyWindow
@ -273,17 +279,12 @@
[super becomeKeyWindow];
}
-(void) restoreParentWindow;
- (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification
{
auto parent = [self parentWindow];
if(parent != nil)
{
[parent removeChildWindow:self];
}
_parent->BringToFront();
}
- (void)windowDidMiniaturize:(NSNotification *)notification
- (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -293,7 +294,7 @@
}
}
- (void)windowDidDeminiaturize:(NSNotification *)notification
- (void)windowDidDeminiaturize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -303,7 +304,7 @@
}
}
- (void)windowDidResize:(NSNotification *)notification
- (void)windowDidResize:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -313,7 +314,7 @@
}
}
- (void)windowWillExitFullScreen:(NSNotification *)notification
- (void)windowWillExitFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -323,7 +324,7 @@
}
}
- (void)windowDidExitFullScreen:(NSNotification *)notification
- (void)windowDidExitFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -346,7 +347,7 @@
}
}
- (void)windowWillEnterFullScreen:(NSNotification *)notification
- (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -356,7 +357,7 @@
}
}
- (void)windowDidEnterFullScreen:(NSNotification *)notification
- (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
@ -367,7 +368,7 @@
}
}
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
- (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame
{
return true;
}
@ -378,11 +379,13 @@
_parent->BaseEvents->Deactivated();
[self showAppMenuOnly];
[self invalidateShadow];
[super resignKeyWindow];
}
- (void)windowDidMove:(NSNotification *)notification
- (void)windowDidMove:(NSNotification *_Nonnull)notification
{
AvnPoint position;
@ -414,7 +417,7 @@
return pt;
}
- (void)sendEvent:(NSEvent *)event
- (void)sendEvent:(NSEvent *_Nonnull)event
{
[super sendEvent:event];
@ -437,8 +440,10 @@
_parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint32>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
}
_parent->BringToFront();
}
break;
break;
case NSEventTypeMouseEntered:
{

2
native/Avalonia.Native/src/OSX/INSWindowHolder.h

@ -11,7 +11,7 @@
struct INSWindowHolder
{
virtual NSWindow* _Nonnull GetNSWindow () = 0;
virtual NSView* _Nonnull GetNSView () = 0;
virtual AvnView* _Nonnull GetNSView () = 0;
};
#endif //AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H

6
native/Avalonia.Native/src/OSX/WindowBaseImpl.h

@ -26,7 +26,7 @@ BEGIN_INTERFACE_MAP()
virtual ~WindowBaseImpl();
WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl);
WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, bool usePanel = false);
virtual HRESULT ObtainNSWindowHandle(void **ret) override;
@ -38,7 +38,7 @@ BEGIN_INTERFACE_MAP()
virtual NSWindow *GetNSWindow() override;
virtual NSView *GetNSView() override;
virtual AvnView *GetNSView() override;
virtual HRESULT Show(bool activate, bool isDialog) override;
@ -99,6 +99,8 @@ BEGIN_INTERFACE_MAP()
virtual bool IsDialog();
id<AvnWindowProtocol> GetWindowProtocol ();
virtual void BringToFront ();
protected:
virtual NSWindowStyleMask GetStyle();

19
native/Avalonia.Native/src/OSX/WindowBaseImpl.mm

@ -21,7 +21,7 @@ WindowBaseImpl::~WindowBaseImpl() {
Window = nullptr;
}
WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) {
WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, bool usePanel) {
_shown = false;
_inResize = false;
BaseEvents = events;
@ -36,8 +36,10 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl)
lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX};
lastMinSize = NSSize { 0, 0 };
Window = nullptr;
lastMenu = nullptr;
CreateNSWindow(usePanel);
InitialiseNSWindow();
}
HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) {
@ -68,7 +70,7 @@ NSWindow *WindowBaseImpl::GetNSWindow() {
return Window;
}
NSView *WindowBaseImpl::GetNSView() {
AvnView *WindowBaseImpl::GetNSView() {
return View;
}
@ -88,7 +90,6 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) {
START_COM_CALL;
@autoreleasepool {
CreateNSWindow(isDialog);
InitialiseNSWindow();
if(hasPosition)
@ -143,8 +144,6 @@ HRESULT WindowBaseImpl::Hide() {
@autoreleasepool {
if (Window != nullptr) {
[Window orderOut:Window];
[GetWindowProtocol() restoreParentWindow];
}
return S_OK;
@ -558,6 +557,8 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) {
CleanNSWindow();
Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()];
[Window setHidesOnDeactivate:false];
}
} else {
if (![Window isKindOfClass:[AvnWindow class]]) {
@ -585,6 +586,7 @@ void WindowBaseImpl::InitialiseNSWindow() {
[Window setOpaque:false];
[Window setHasShadow:true];
[Window invalidateShadow];
if (lastMenu != nullptr) {
@ -608,6 +610,11 @@ id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() {
return (id <AvnWindowProtocol>) Window;
}
void WindowBaseImpl::BringToFront()
{
// do nothing.
}
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl)
{
@autoreleasepool

8
native/Avalonia.Native/src/OSX/WindowImpl.h

@ -8,10 +8,12 @@
#import "WindowBaseImpl.h"
#include "IWindowStateChanged.h"
#include <list>
class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged
{
private:
bool _isEnabled;
bool _canResize;
bool _fullScreenActive;
SystemDecorations _decorations;
@ -22,6 +24,8 @@ private:
bool _transitioningWindowState;
bool _isClientAreaExtended;
bool _isDialog;
WindowImpl* _parent;
std::list<WindowImpl*> _children;
AvnExtendClientAreaChromeHints _extendClientHints;
FORWARD_IUNKNOWN()
@ -90,6 +94,10 @@ BEGIN_INTERFACE_MAP()
virtual bool IsDialog() override;
virtual void OnInitialiseNSWindow() override;
virtual void BringToFront () override;
bool CanBecomeKeyWindow ();
protected:
virtual NSWindowStyleMask GetStyle() override;

112
native/Avalonia.Native/src/OSX/WindowImpl.mm

@ -10,6 +10,8 @@
#include "WindowProtocol.h"
WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) {
_isEnabled = true;
_children = std::list<WindowImpl*>();
_isClientAreaExtended = false;
_extendClientHints = AvnDefaultChrome;
_fullScreenActive = false;
@ -20,6 +22,7 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase
_lastWindowState = Normal;
_actualWindowState = Normal;
_lastTitle = @"";
_parent = nullptr;
WindowEvents = events;
}
@ -28,24 +31,12 @@ void WindowImpl::HideOrShowTrafficLights() {
return;
}
for (id subview in Window.contentView.superview.subviews) {
if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")]) {
NSView *titlebarView = [subview subviews][0];
for (id button in titlebarView.subviews) {
if ([button isKindOfClass:[NSButton class]]) {
if (_isClientAreaExtended) {
auto wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
[button setHidden:!wantsChrome];
} else {
[button setHidden:(_decorations != SystemDecorationsFull)];
}
[button setWantsLayer:true];
}
}
}
}
bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull;
[[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights];
[[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights];
[[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights];
}
void WindowImpl::OnInitialiseNSWindow(){
@ -61,6 +52,11 @@ void WindowImpl::OnInitialiseNSWindow(){
[GetWindowProtocol() setIsExtended:true];
SetExtendClientArea(true);
}
if(_parent != nullptr)
{
SetParent(_parent);
}
}
HRESULT WindowImpl::Show(bool activate, bool isDialog) {
@ -81,7 +77,9 @@ HRESULT WindowImpl::SetEnabled(bool enable) {
START_COM_CALL;
@autoreleasepool {
_isEnabled = enable;
[GetWindowProtocol() setEnabled:enable];
UpdateStyle();
return S_OK;
}
}
@ -90,26 +88,68 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) {
START_COM_CALL;
@autoreleasepool {
if (parent == nullptr)
return E_POINTER;
if(_parent != nullptr)
{
_parent->_children.remove(this);
_parent->BringToFront();
}
auto cparent = dynamic_cast<WindowImpl *>(parent);
if (cparent == nullptr)
return E_INVALIDARG;
// If one tries to show a child window with a minimized parent window, then the parent window will be
// restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive
// state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
if (cparent->WindowState() == Minimized)
cparent->SetWindowState(Normal);
_parent = cparent;
if(_parent != nullptr && Window != nullptr){
// If one tries to show a child window with a minimized parent window, then the parent window will be
// restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive
// state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
if (cparent->WindowState() == Minimized)
cparent->SetWindowState(Normal);
[Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
cparent->_children.push_back(this);
UpdateStyle();
}
[Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
[cparent->Window addChildWindow:Window ordered:NSWindowAbove];
return S_OK;
}
}
UpdateStyle();
void WindowImpl::BringToFront()
{
if(Window != nullptr)
{
if(IsDialog())
{
Activate();
}
else
{
[Window orderFront:nullptr];
}
[Window invalidateShadow];
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
(*iterator)->BringToFront();
}
}
}
return S_OK;
bool WindowImpl::CanBecomeKeyWindow()
{
for(auto iterator = _children.begin(); iterator != _children.end(); iterator++)
{
if((*iterator)->IsDialog())
{
return false;
}
}
return true;
}
void WindowImpl::StartStateTransition() {
@ -523,7 +563,7 @@ bool WindowImpl::IsDialog() {
}
NSWindowStyleMask WindowImpl::GetStyle() {
unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless;
unsigned long s = NSWindowStyleMaskBorderless;
switch (_decorations) {
case SystemDecorationsNone:
@ -535,15 +575,15 @@ NSWindowStyleMask WindowImpl::GetStyle() {
break;
case SystemDecorationsFull:
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskBorderless;
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
if (_canResize) {
if (_canResize && _isEnabled) {
s = s | NSWindowStyleMaskResizable;
}
break;
}
if ([Window parentWindow] == nullptr) {
if (!IsDialog()) {
s |= NSWindowStyleMaskMiniaturizable;
}

1
native/Avalonia.Native/src/OSX/WindowProtocol.h

@ -11,7 +11,6 @@
@protocol AvnWindowProtocol
-(void) pollModalSession: (NSModalSession _Nonnull) session;
-(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents;
-(void) setEnabled: (bool) enable;
-(void) showAppMenuOnly;

2
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -20,7 +20,7 @@
Text="Window dialogs" />
<Button Name="DecoratedWindow">Decorated _window</Button>
<Button Name="DecoratedWindowDialog">Decorated w_indow (dialog)</Button>
<Button Name="Dialog">_Dialog</Button>
<Button Name="Dialog" ToolTip.Tip="Shows a dialog">_Dialog</Button>
<Button Name="DialogNoTaskbar">Dialog (_No taskbar icon)</Button>
<Button Name="OwnedWindow">Own_ed window</Button>
<Button Name="OwnedWindowNoTaskbar">Owned window (No tas_kbar icon)</Button>

13
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -151,6 +151,7 @@ namespace ControlCatalog.Pages
private Window CreateSampleWindow()
{
Button button;
Button dialogButton;
var window = new Window
{
@ -167,6 +168,12 @@ namespace ControlCatalog.Pages
HorizontalAlignment = HorizontalAlignment.Center,
Content = "Click to close",
IsDefault = true
}),
(dialogButton = new Button
{
HorizontalAlignment = HorizontalAlignment.Center,
Content = "Dialog",
IsDefault = false
})
}
},
@ -174,6 +181,12 @@ namespace ControlCatalog.Pages
};
button.Click += (_, __) => window.Close();
dialogButton.Click += (_, __) =>
{
var dialog = CreateSampleWindow();
dialog.Height = 200;
dialog.ShowDialog(window);
};
return window;
}

9
src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs

@ -33,7 +33,14 @@ namespace Avalonia.Data.Converters
if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1)
{
return new MethodToCommandConverter(d);
if (d.Method.IsPrivate == false)
{
return new MethodToCommandConverter(d);
}
else
{
return new BindingNotification(new InvalidCastException("You can't bind to private methods!"), BindingErrorType.Error);
}
}
if (TypeUtilities.TryConvert(targetType, value, culture, out var result))

4
src/Avalonia.Base/Styling/Style.cs

@ -94,7 +94,6 @@ namespace Avalonia.Styling
/// <summary>
/// Gets the style's setters.
/// </summary>
[Content]
public IList<ISetter> Setters => _setters ??= new List<ISetter>();
/// <summary>
@ -107,6 +106,9 @@ namespace Avalonia.Styling
public event EventHandler? OwnerChanged;
public void Add(ISetter setter) => Setters.Add(setter);
public void Add(IStyle style) => Children.Add(style);
public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host)
{
target = target ?? throw new ArgumentNullException(nameof(target));

5
src/Avalonia.Controls/ContextMenu.cs

@ -450,6 +450,11 @@ namespace Avalonia.Controls
if (sender is Control control
&& control.ContextMenu is ContextMenu contextMenu)
{
if (contextMenu._popup?.Parent == control)
{
((ISetLogicalParent)contextMenu._popup).SetParent(null);
}
contextMenu.Close();
}
}

5
src/Avalonia.Controls/Flyouts/FlyoutBase.cs

@ -175,7 +175,8 @@ namespace Avalonia.Controls.Primitives
IsOpen = false;
Popup.IsOpen = false;
((ISetLogicalParent)Popup).SetParent(null);
// Ensure this isn't active
_transientDisposable?.Dispose();
_transientDisposable = null;
@ -218,7 +219,7 @@ namespace Avalonia.Controls.Primitives
((ISetLogicalParent)Popup).SetParent(null);
}
if (Popup.PlacementTarget != placementTarget)
if (Popup.Parent == null || Popup.PlacementTarget != placementTarget)
{
Popup.PlacementTarget = Target = placementTarget;
((ISetLogicalParent)Popup).SetParent(placementTarget);

74
src/Avalonia.Themes.Fluent/Controls/Button.xaml

@ -40,53 +40,49 @@
</ControlTemplate>
</Setter>
<Style.Children>
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
</Style>
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
</Style>
<Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
<Style Selector="^.accent">
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" />
</Style>
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" />
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
</Style>
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" />
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" />
</Style>
<Style Selector="^.accent">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" />
</Style>
<Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" />
</Style>
<Style Selector="^:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" />
</Style>
<Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Style.Children>
<Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" />
<Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" />
</Style>
</Style.Children>
</Style>
</Style>
<Style Selector="Button, RepeatButton, ToggleButton, DropDownButton">

464
src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml

@ -56,266 +56,242 @@
</ControlTemplate>
</Setter>
<Style.Children>
<!-- Unchecked Normal State -->
<!-- Unchecked Normal State -->
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUnchecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUnchecked}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUnchecked}" />
<Setter Property="Opacity" Value="0" />
</Style>
<!-- Unchecked PointerOver State -->
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}" />
</Style>
</Style>
<!-- Unchecked Pressed State -->
<Style Selector="^:pressed">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUnchecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUnchecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUnchecked}" />
<Setter Property="Opacity" Value="0" />
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPressed}" />
</Style>
</Style>
<!-- Unchecked PointerOver State -->
<!-- Unchecked Disabled state -->
<Style Selector="^:disabled">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedDisabled}" />
</Style>
</Style>
<Style Selector="^:checked">
<!-- Checked Normal State -->
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" />
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundChecked}" />
<Setter Property="Data" Value="M1507 31L438 1101L-119 543L-29 453L438 919L1417 -59L1507 31Z" />
<Setter Property="Width" Value="9" />
<Setter Property="Opacity" Value="1" />
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
<!-- Checked PointerOver State -->
<Style Selector="^:pointerover">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}" />
</Style>
</Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPointerOver}" />
</Style>
</Style>
<!-- Unchecked Pressed State -->
<!-- Checked Pressed State -->
<Style Selector="^:pressed">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPressed}" />
</Style>
</Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPressed}" />
</Style>
</Style>
<!-- Unchecked Disabled state -->
<!-- Checked Disabled State -->
<Style Selector="^:disabled">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedDisabled}" />
</Style>
</Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedDisabled}" />
</Style>
</Style>
</Style>
<Style Selector="^:checked">
<!-- Checked Normal State -->
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" />
<Style.Children>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillChecked}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundChecked}" />
<Setter Property="Data" Value="M1507 31L438 1101L-119 543L-29 453L438 919L1417 -59L1507 31Z" />
<Setter Property="Width" Value="9" />
<Setter Property="Opacity" Value="1" />
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
<!-- Checked PointerOver State -->
<Style Selector="^:pointerover">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPointerOver}" />
</Style>
</Style.Children>
</Style>
<!-- Checked Pressed State -->
<Style Selector="^:pressed">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedPressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedPressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedPressed}" />
</Style>
</Style.Children>
</Style>
<!-- Checked Disabled State -->
<Style Selector="^:disabled">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundCheckedDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeCheckedDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillCheckedDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundCheckedDisabled}" />
</Style>
</Style.Children>
</Style>
</Style.Children>
<Style Selector="^:indeterminate">
<!-- Indeterminate Normal State -->
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" />
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminate}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminate}" />
</Style>
<Style Selector="^:indeterminate">
<!-- Indeterminate Normal State -->
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" />
<Style.Children>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminate}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminate}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminate}" />
<Setter Property="Data" Value="M1536 1536v-1024h-1024v1024h1024z" />
<Setter Property="Width" Value="7" />
<Setter Property="Opacity" Value="1" />
</Style>
<!-- Indeterminate PointerOver State -->
<Style Selector="^:pointerover">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePointerOver}" />
</Style>
</Style.Children>
</Style>
<!-- Indeterminate Pressed State -->
<Style Selector="^:pressed">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePressed}" />
</Style>
</Style.Children>
</Style>
<!-- Indeterminate Disabled State -->
<Style Selector="^:disabled">
<Style.Children>
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminateDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminateDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminateDisabled}" />
</Style>
</Style.Children>
</Style>
</Style.Children>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminate}" />
<Setter Property="Data" Value="M1536 1536v-1024h-1024v1024h1024z" />
<Setter Property="Width" Value="7" />
<Setter Property="Opacity" Value="1" />
</Style>
<!-- Indeterminate PointerOver State -->
<Style Selector="^:pointerover">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePointerOver}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePointerOver}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePointerOver}" />
</Style>
</Style>
<!-- Indeterminate Pressed State -->
<Style Selector="^:pressed">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminatePressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminatePressed}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminatePressed}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminatePressed}" />
</Style>
</Style>
<!-- Indeterminate Disabled State -->
<Style Selector="^:disabled">
<Style Selector="^ /template/ ContentPresenter#ContentPresenter">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminateDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Border#NormalRectangle">
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeIndeterminateDisabled}" />
<Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillIndeterminateDisabled}" />
</Style>
<Style Selector="^ /template/ Path#CheckGlyph">
<Setter Property="Fill" Value="{DynamicResource CheckBoxCheckGlyphForegroundIndeterminateDisabled}" />
</Style>
</Style>
</Style.Children>
</Style>
</Style>

5
src/Web/Avalonia.Web.Blazor/AvaloniaView.razor

@ -12,7 +12,10 @@
<div id="nativeControlsContainer" @ref="_nativeControlsContainer" />
<input id="inputElement" @ref="_inputElement" type="text" oninput="@OnInput"/>
<input id="inputElement" @ref="_inputElement" type="text" oninput="@OnInput"
onpaste="return false;"
oncopy="return false;"
oncut="return false;"/>
</div>
<style>

34
src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Microsoft.JSInterop;
namespace Avalonia.Web.Blazor
{
internal class ClipboardImpl : IClipboard
{
public async Task<string> GetTextAsync()
{
return await AvaloniaLocator.Current.GetRequiredService<IJSInProcessRuntime>().
InvokeAsync<string>("navigator.clipboard.readText");
}
public async Task SetTextAsync(string text)
{
await AvaloniaLocator.Current.GetRequiredService<IJSInProcessRuntime>().
InvokeAsync<string>("navigator.clipboard.writeText",text);
}
public async Task ClearAsync() => await SetTextAsync("");
public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
public Task<string[]> GetFormatsAsync() => Task.FromResult(Array.Empty<string>());
public Task<object> GetDataAsync(string format) => Task.FromResult<object>(new());
}
}

15
src/Web/Avalonia.Web.Blazor/WinStubs.cs

@ -8,21 +8,6 @@ using Avalonia.Platform;
namespace Avalonia.Web.Blazor
{
internal class ClipboardStub : IClipboard
{
public Task<string> GetTextAsync() => Task.FromResult("");
public Task SetTextAsync(string text) => Task.CompletedTask;
public Task ClearAsync() => Task.CompletedTask;
public Task SetDataObjectAsync(IDataObject data) => Task.CompletedTask;
public Task<string[]> GetFormatsAsync() => Task.FromResult(Array.Empty<string>());
public Task<object> GetDataAsync(string format) => Task.FromResult<object>(new ());
}
internal class IconLoaderStub : IPlatformIconLoader
{
private class IconStub : IWindowIconImpl

2
src/Web/Avalonia.Web.Blazor/WindowingPlatform.cs

@ -34,7 +34,7 @@ namespace Avalonia.Web.Blazor
var instance = new BlazorWindowingPlatform();
s_keyboard = new KeyboardDevice();
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardStub>()
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<ICursorFactory>().ToSingleton<CssCursorFactory>()
.Bind<IKeyboardDevice>().ToConstant(s_keyboard)
.Bind<IPlatformSettings>().ToConstant(instance)

21
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@ -446,6 +446,27 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Should_Reset_Popup_Parent_On_Target_Detached()
{
using (Application())
{
var userControl = new UserControl();
var window = PreparedWindow(userControl);
window.Show();
var menu = new ContextMenu();
userControl.ContextMenu = menu;
menu.Open();
var popup = Assert.IsType<Popup>(menu.Parent);
Assert.NotNull(popup.Parent);
window.Content = null;
Assert.Null(popup.Parent);
}
}
[Fact]
public void Context_Menu_In_Resources_Can_Be_Shared()
{

47
tests/Avalonia.Controls.UnitTests/FlyoutTests.cs

@ -432,6 +432,48 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Should_Reset_Popup_Parent_On_Target_Detached()
{
using (CreateServicesWithFocus())
{
var userControl = new UserControl();
var window = PreparedWindow(userControl);
window.Show();
var flyout = new TestFlyout();
flyout.ShowAt(userControl);
var popup = Assert.IsType<Popup>(flyout.Popup);
Assert.NotNull(popup.Parent);
window.Content = null;
Assert.Null(popup.Parent);
}
}
[Fact]
public void Should_Reset_Popup_Parent_On_Target_Attach_Following_Detach()
{
using (CreateServicesWithFocus())
{
var userControl = new UserControl();
var window = PreparedWindow(userControl);
window.Show();
var flyout = new TestFlyout();
flyout.ShowAt(userControl);
var popup = Assert.IsType<Popup>(flyout.Popup);
Assert.NotNull(popup.Parent);
flyout.Hide();
flyout.ShowAt(userControl);
Assert.NotNull(popup.Parent);
}
}
[Fact]
public void ContextFlyout_Can_Be_Set_In_Styles()
{
@ -549,5 +591,10 @@ namespace Avalonia.Controls.UnitTests
new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed),
KeyModifiers.None);
}
public class TestFlyout : Flyout
{
public new Popup Popup => base.Popup;
}
}
}

32
tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs

@ -0,0 +1,32 @@
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Xunit;
namespace Avalonia.Markup.UnitTests.Data
{
public class BindingTests_Method
{
[Fact]
public void Binding_To_Private_Methods_Shouldnt_Work()
{
var vm = new TestClass();
var target = new Button
{
DataContext = vm,
[!Button.CommandProperty] = new Binding("MyMethod"),
};
target.RaiseEvent(new RoutedEventArgs(AccessKeyHandler.AccessKeyPressedEvent));
Assert.False(vm.IsSet);
}
class TestClass
{
public bool IsSet { get; set; }
private void MyMethod() => IsSet = true;
}
}
}

8
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

@ -628,11 +628,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.Styles>
<Style Selector='Border'>
<Style.Children>
<Style Selector='^.foo'>
<Setter Property='Background' Value='Red'/>
</Style>
</Style.Children>
<Style Selector='^.foo'>
<Setter Property='Background' Value='Red'/>
</Style>
</Style>
</Window.Styles>
<StackPanel>

Loading…
Cancel
Save