1837 changed files with 79804 additions and 54919 deletions
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -1,16 +0,0 @@ |
|||
<Project> |
|||
<ItemGroup Condition="'$(AndroidApplication)' == 'true'"> |
|||
<!-- WORKAROUND: The packages below are transitively referenced by System.Memory, |
|||
but Xamarin.Android applications need the newest versions directly referenced for the linker. --> |
|||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.6.0" /> |
|||
<PackageReference Include="System.Buffers" Version="4.5.0" /> |
|||
</ItemGroup> |
|||
<Target Name="_RemoveNonExistingResgenFile" BeforeTargets="CoreCompile" Condition="'$(_SdkSetAndroidResgenFile)' == 'true' And '$(AndroidResgenFile)' != '' And !Exists('$(AndroidResgenFile)')"> |
|||
<ItemGroup> |
|||
<Compile Remove="$(AndroidResgenFile)"/> |
|||
</ItemGroup> |
|||
</Target> |
|||
<PropertyGroup> |
|||
<DesignTimeBuild>false</DesignTimeBuild> |
|||
</PropertyGroup> |
|||
</Project> |
|||
@ -1,22 +1,13 @@ |
|||
<Project> |
|||
<ItemGroup> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Base/Avalonia.Base.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Animation/Avalonia.Animation.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Controls/Avalonia.Controls.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Input/Avalonia.Input.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Interactivity/Avalonia.Interactivity.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Layout/Avalonia.Layout.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Visuals/Avalonia.Visuals.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Styling/Avalonia.Styling.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.OpenGL/Avalonia.OpenGL.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Dialogs/Avalonia.Dialogs.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj" Condition="'$(TargetFramework)' != 'netstandard2.0'" /> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,9 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\DevAnalyzers\DevAnalyzers.csproj" |
|||
PrivateAssets="all" |
|||
ReferenceOutputAssembly="false" |
|||
OutputItemType="Analyzer" |
|||
SetTargetFramework="TargetFramework=netstandard2.0"/> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,7 +1,7 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="HarfBuzzSharp" Version="2.8.2-preview.178" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2-preview.178" /> |
|||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2-preview.178"/> |
|||
<PackageReference Include="HarfBuzzSharp" Version="2.8.2-preview.254" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2-preview.254" /> |
|||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2-preview.254"/> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,5 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,5 +0,0 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="Magick.NET-Q16-AnyCPU" Version="7.9.0.2" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,7 +1,7 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="SkiaSharp" Version="2.88.0-preview.178" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.0-preview.178" /> |
|||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.0-preview.178"/> |
|||
<PackageReference Include="SkiaSharp" Version="2.88.0-preview.254" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.0-preview.254" /> |
|||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.0-preview.254"/> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,10 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<ProjectReference |
|||
Include="$(MSBuildThisFileDirectory)/../src/Avalonia.SourceGenerator/Avalonia.SourceGenerator.csproj" |
|||
OutputItemType="Analyzer" |
|||
ReferenceOutputAssembly="false" |
|||
PrivateAssets="all" /> |
|||
<Compile Include="$(MSBuildThisFileDirectory)/../src/Shared/SourceGeneratorAttributes.cs" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -1,5 +1,6 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="System.Drawing.Common" Version="4.5.0" /> |
|||
<PackageReference Condition="'$(TargetFramework)'!='netstandard2.0'" Include="System.Drawing.Common" Version="6.0.0" /> |
|||
<PackageReference Condition="'$(TargetFramework)'=='netstandard2.0'" Include="System.Drawing.Common" Version="4.5.0" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,17 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 05/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#import <Foundation/Foundation.h> |
|||
#include "avalonia-native.h" |
|||
|
|||
@interface AutoFitContentView : NSView |
|||
-(AutoFitContentView* _Nonnull) initWithContent: (NSView* _Nonnull) content; |
|||
-(void) ShowTitleBar: (bool) show; |
|||
-(void) SetTitleBarHeightHint: (double) height; |
|||
|
|||
-(void) ShowBlur: (bool) show; |
|||
@end |
|||
@ -0,0 +1,106 @@ |
|||
// |
|||
// Created by Dan Walmsley on 05/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#include "AvnView.h" |
|||
#include "AutoFitContentView.h" |
|||
#include "WindowInterfaces.h" |
|||
#include "WindowProtocol.h" |
|||
|
|||
@implementation AutoFitContentView |
|||
{ |
|||
NSVisualEffectView* _titleBarMaterial; |
|||
NSBox* _titleBarUnderline; |
|||
NSView* _content; |
|||
NSVisualEffectView* _blurBehind; |
|||
double _titleBarHeightHint; |
|||
bool _settingSize; |
|||
} |
|||
|
|||
-(AutoFitContentView* _Nonnull) initWithContent:(NSView *)content |
|||
{ |
|||
_titleBarHeightHint = -1; |
|||
_content = content; |
|||
_settingSize = false; |
|||
|
|||
[self setAutoresizesSubviews:true]; |
|||
[self setWantsLayer:true]; |
|||
|
|||
_titleBarMaterial = [NSVisualEffectView new]; |
|||
[_titleBarMaterial setBlendingMode:NSVisualEffectBlendingModeWithinWindow]; |
|||
[_titleBarMaterial setMaterial:NSVisualEffectMaterialTitlebar]; |
|||
[_titleBarMaterial setWantsLayer:true]; |
|||
_titleBarMaterial.hidden = true; |
|||
|
|||
_titleBarUnderline = [NSBox new]; |
|||
_titleBarUnderline.boxType = NSBoxSeparator; |
|||
_titleBarUnderline.fillColor = [NSColor underPageBackgroundColor]; |
|||
_titleBarUnderline.hidden = true; |
|||
|
|||
[self addSubview:_titleBarMaterial]; |
|||
[self addSubview:_titleBarUnderline]; |
|||
|
|||
_blurBehind = [NSVisualEffectView new]; |
|||
[_blurBehind setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; |
|||
[_blurBehind setMaterial:NSVisualEffectMaterialLight]; |
|||
[_blurBehind setWantsLayer:true]; |
|||
_blurBehind.hidden = true; |
|||
|
|||
[_blurBehind setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
|||
[_content setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; |
|||
|
|||
[self addSubview:_blurBehind]; |
|||
[self addSubview:_content]; |
|||
|
|||
[self setWantsLayer:true]; |
|||
return self; |
|||
} |
|||
|
|||
-(void) ShowBlur:(bool)show |
|||
{ |
|||
_blurBehind.hidden = !show; |
|||
} |
|||
|
|||
-(void) ShowTitleBar: (bool) show |
|||
{ |
|||
_titleBarMaterial.hidden = !show; |
|||
_titleBarUnderline.hidden = !show; |
|||
} |
|||
|
|||
-(void) SetTitleBarHeightHint: (double) height |
|||
{ |
|||
_titleBarHeightHint = height; |
|||
|
|||
[self setFrameSize:self.frame.size]; |
|||
} |
|||
|
|||
-(void)setFrameSize:(NSSize)newSize |
|||
{ |
|||
if(_settingSize) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_settingSize = true; |
|||
[super setFrameSize:newSize]; |
|||
|
|||
auto window = static_cast<id <AvnWindowProtocol>>([self window]); |
|||
|
|||
// TODO get actual titlebar size |
|||
|
|||
double height = _titleBarHeightHint == -1 ? [window getExtendedTitleBarHeight] : _titleBarHeightHint; |
|||
|
|||
NSRect tbar; |
|||
tbar.origin.x = 0; |
|||
tbar.origin.y = newSize.height - height; |
|||
tbar.size.width = newSize.width; |
|||
tbar.size.height = height; |
|||
|
|||
[_titleBarMaterial setFrame:tbar]; |
|||
tbar.size.height = height < 1 ? 0 : 1; |
|||
[_titleBarUnderline setFrame:tbar]; |
|||
|
|||
_settingSize = false; |
|||
} |
|||
@end |
|||
@ -0,0 +1,11 @@ |
|||
// |
|||
// Created by Dan Walmsley on 06/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#pragma once |
|||
|
|||
#define IS_NSPANEL |
|||
|
|||
#include "AvnWindow.mm" |
|||
|
|||
@ -0,0 +1,27 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 05/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
#pragma once |
|||
#import <Foundation/Foundation.h> |
|||
|
|||
|
|||
#import <Foundation/Foundation.h> |
|||
#import <AppKit/AppKit.h> |
|||
#include "common.h" |
|||
#include "WindowImpl.h" |
|||
#include "KeyTransform.h" |
|||
|
|||
@class AvnAccessibilityElement; |
|||
|
|||
@interface AvnView : NSView<NSTextInputClient, NSDraggingDestination> |
|||
-(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent; |
|||
-(NSEvent* _Nonnull) lastMouseDownEvent; |
|||
-(AvnPoint) translateLocalPoint:(AvnPoint)pt; |
|||
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose; |
|||
-(void) onClosed; |
|||
|
|||
-(AvnPlatformResizeReason) getResizeReason; |
|||
-(void) setResizeReason:(AvnPlatformResizeReason)reason; |
|||
+ (AvnPoint)toAvnPoint:(CGPoint)p; |
|||
@end |
|||
@ -0,0 +1,712 @@ |
|||
// |
|||
// Created by Dan Walmsley on 05/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#include "AvnView.h" |
|||
#include "automation.h" |
|||
#import "WindowInterfaces.h" |
|||
|
|||
@implementation AvnView |
|||
{ |
|||
ComPtr<WindowBaseImpl> _parent; |
|||
NSTrackingArea* _area; |
|||
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed; |
|||
AvnInputModifiers _modifierState; |
|||
NSEvent* _lastMouseDownEvent; |
|||
bool _lastKeyHandled; |
|||
AvnPixelSize _lastPixelSize; |
|||
NSObject<IRenderTarget>* _renderTarget; |
|||
AvnPlatformResizeReason _resizeReason; |
|||
AvnAccessibilityElement* _accessibilityChild; |
|||
} |
|||
|
|||
- (void)onClosed |
|||
{ |
|||
@synchronized (self) |
|||
{ |
|||
_parent = nullptr; |
|||
} |
|||
} |
|||
|
|||
- (NSEvent*) lastMouseDownEvent |
|||
{ |
|||
return _lastMouseDownEvent; |
|||
} |
|||
|
|||
- (void) updateRenderTarget |
|||
{ |
|||
[_renderTarget resize:_lastPixelSize withScale:static_cast<float>([[self window] backingScaleFactor])]; |
|||
[self setNeedsDisplayInRect:[self frame]]; |
|||
} |
|||
|
|||
-(AvnView*) initWithParent: (WindowBaseImpl*) parent |
|||
{ |
|||
self = [super init]; |
|||
_renderTarget = parent->renderTarget; |
|||
[self setWantsLayer:YES]; |
|||
[self setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize]; |
|||
|
|||
_parent = parent; |
|||
_area = nullptr; |
|||
_lastPixelSize.Height = 100; |
|||
_lastPixelSize.Width = 100; |
|||
[self registerForDraggedTypes: @[@"public.data", GetAvnCustomDataType()]]; |
|||
|
|||
_modifierState = AvnInputModifiersNone; |
|||
return self; |
|||
} |
|||
|
|||
- (BOOL)isFlipped |
|||
{ |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)wantsUpdateLayer |
|||
{ |
|||
return YES; |
|||
} |
|||
|
|||
- (void)setLayer:(CALayer *)layer |
|||
{ |
|||
[_renderTarget setNewLayer: layer]; |
|||
[super setLayer: layer]; |
|||
} |
|||
|
|||
- (BOOL)isOpaque |
|||
{ |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)acceptsFirstResponder |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
- (BOOL)acceptsFirstMouse:(NSEvent *)event |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
- (BOOL)canBecomeKeyView |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
-(void)setFrameSize:(NSSize)newSize |
|||
{ |
|||
[super setFrameSize:newSize]; |
|||
|
|||
if(_area != nullptr) |
|||
{ |
|||
[self removeTrackingArea:_area]; |
|||
_area = nullptr; |
|||
} |
|||
|
|||
if (_parent == nullptr) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
NSRect rect = NSZeroRect; |
|||
rect.size = newSize; |
|||
|
|||
NSTrackingAreaOptions options = NSTrackingActiveAlways | NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingEnabledDuringMouseDrag; |
|||
_area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr]; |
|||
[self addTrackingArea:_area]; |
|||
|
|||
_parent->UpdateCursor(); |
|||
|
|||
auto fsize = [self convertSizeToBacking: [self frame].size]; |
|||
|
|||
if(_lastPixelSize.Width != (int)fsize.width || _lastPixelSize.Height != (int)fsize.height) |
|||
{ |
|||
_lastPixelSize.Width = (int)fsize.width; |
|||
_lastPixelSize.Height = (int)fsize.height; |
|||
[self updateRenderTarget]; |
|||
|
|||
auto reason = [self inLiveResize] ? ResizeUser : _resizeReason; |
|||
_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason); |
|||
} |
|||
} |
|||
|
|||
- (void)updateLayer |
|||
{ |
|||
AvnInsidePotentialDeadlock deadlock; |
|||
if (_parent == nullptr) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_parent->BaseEvents->RunRenderPriorityJobs(); |
|||
|
|||
if (_parent == nullptr) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
_parent->BaseEvents->Paint(); |
|||
} |
|||
|
|||
- (void)drawRect:(NSRect)dirtyRect |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
-(void) setSwRenderedFrame: (AvnFramebuffer*) fb dispose: (IUnknown*) dispose |
|||
{ |
|||
@autoreleasepool { |
|||
[_renderTarget setSwFrame:fb]; |
|||
dispose->Release(); |
|||
} |
|||
} |
|||
|
|||
- (AvnPoint) translateLocalPoint:(AvnPoint)pt |
|||
{ |
|||
pt.Y = [self bounds].size.height - pt.Y; |
|||
return pt; |
|||
} |
|||
|
|||
+ (AvnPoint)toAvnPoint:(CGPoint)p |
|||
{ |
|||
AvnPoint result; |
|||
|
|||
result.X = p.x; |
|||
result.Y = p.y; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
- (void) viewDidChangeBackingProperties |
|||
{ |
|||
auto fsize = [self convertSizeToBacking: [self frame].size]; |
|||
_lastPixelSize.Width = (int)fsize.width; |
|||
_lastPixelSize.Height = (int)fsize.height; |
|||
[self updateRenderTarget]; |
|||
|
|||
if(_parent != nullptr) |
|||
{ |
|||
_parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]); |
|||
} |
|||
|
|||
[super viewDidChangeBackingProperties]; |
|||
} |
|||
|
|||
- (bool) ignoreUserInput:(bool)trigerInputWhenDisabled |
|||
{ |
|||
if(_parent == nullptr) |
|||
{ |
|||
return TRUE; |
|||
} |
|||
|
|||
auto parentWindow = _parent->GetWindowProtocol(); |
|||
|
|||
if(parentWindow == nil || ![parentWindow shouldTryToHandleEvents]) |
|||
{ |
|||
if(trigerInputWhenDisabled) |
|||
{ |
|||
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw()); |
|||
|
|||
if(window != nullptr) |
|||
{ |
|||
window->WindowEvents->GotInputWhenDisabled(); |
|||
} |
|||
} |
|||
|
|||
return TRUE; |
|||
} |
|||
|
|||
return FALSE; |
|||
} |
|||
|
|||
- (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type |
|||
{ |
|||
bool triggerInputWhenDisabled = type != Move; |
|||
|
|||
if([self ignoreUserInput: triggerInputWhenDisabled]) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
auto localPoint = [self convertPoint:[event locationInWindow] toView:self]; |
|||
auto avnPoint = [AvnView toAvnPoint:localPoint]; |
|||
auto point = [self translateLocalPoint:avnPoint]; |
|||
AvnVector delta = { 0, 0}; |
|||
|
|||
if(type == Wheel) |
|||
{ |
|||
auto speed = 5; |
|||
|
|||
if([event hasPreciseScrollingDeltas]) |
|||
{ |
|||
speed = 50; |
|||
} |
|||
|
|||
delta.X = [event scrollingDeltaX] / speed; |
|||
delta.Y = [event scrollingDeltaY] / speed; |
|||
|
|||
if(delta.X == 0 && delta.Y == 0) |
|||
{ |
|||
return; |
|||
} |
|||
} |
|||
else if (type == Magnify) |
|||
{ |
|||
delta.X = delta.Y = [event magnification]; |
|||
} |
|||
else if (type == Rotate) |
|||
{ |
|||
delta.X = delta.Y = [event rotation]; |
|||
} |
|||
else if (type == Swipe) |
|||
{ |
|||
delta.X = [event deltaX]; |
|||
delta.Y = [event deltaY]; |
|||
} |
|||
|
|||
uint32 timestamp = static_cast<uint32>([event timestamp] * 1000); |
|||
auto modifiers = [self getModifiers:[event modifierFlags]]; |
|||
|
|||
if(type != Move || |
|||
( |
|||
[self window] != nil && |
|||
( |
|||
[[self window] firstResponder] == nil |
|||
|| ![[[self window] firstResponder] isKindOfClass: [NSView class]] |
|||
) |
|||
) |
|||
) |
|||
[self becomeFirstResponder]; |
|||
|
|||
if(_parent != nullptr) |
|||
{ |
|||
_parent->BaseEvents->RawMouseEvent(type, timestamp, modifiers, point, delta); |
|||
} |
|||
|
|||
[super mouseMoved:event]; |
|||
} |
|||
|
|||
- (BOOL) resignFirstResponder |
|||
{ |
|||
_parent->BaseEvents->LostFocus(); |
|||
return YES; |
|||
} |
|||
|
|||
- (void)mouseMoved:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Move]; |
|||
} |
|||
|
|||
- (void)mouseDown:(NSEvent *)event |
|||
{ |
|||
_isLeftPressed = true; |
|||
_lastMouseDownEvent = event; |
|||
[self mouseEvent:event withType:LeftButtonDown]; |
|||
} |
|||
|
|||
- (void)otherMouseDown:(NSEvent *)event |
|||
{ |
|||
_lastMouseDownEvent = event; |
|||
|
|||
switch(event.buttonNumber) |
|||
{ |
|||
case 2: |
|||
case 3: |
|||
_isMiddlePressed = true; |
|||
[self mouseEvent:event withType:MiddleButtonDown]; |
|||
break; |
|||
case 4: |
|||
_isXButton1Pressed = true; |
|||
[self mouseEvent:event withType:XButton1Down]; |
|||
break; |
|||
case 5: |
|||
_isXButton2Pressed = true; |
|||
[self mouseEvent:event withType:XButton2Down]; |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
- (void)rightMouseDown:(NSEvent *)event |
|||
{ |
|||
_isRightPressed = true; |
|||
_lastMouseDownEvent = event; |
|||
[self mouseEvent:event withType:RightButtonDown]; |
|||
} |
|||
|
|||
- (void)mouseUp:(NSEvent *)event |
|||
{ |
|||
_isLeftPressed = false; |
|||
[self mouseEvent:event withType:LeftButtonUp]; |
|||
} |
|||
|
|||
- (void)otherMouseUp:(NSEvent *)event |
|||
{ |
|||
switch(event.buttonNumber) |
|||
{ |
|||
case 2: |
|||
case 3: |
|||
_isMiddlePressed = false; |
|||
[self mouseEvent:event withType:MiddleButtonUp]; |
|||
break; |
|||
case 4: |
|||
_isXButton1Pressed = false; |
|||
[self mouseEvent:event withType:XButton1Up]; |
|||
break; |
|||
case 5: |
|||
_isXButton2Pressed = false; |
|||
[self mouseEvent:event withType:XButton2Up]; |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
- (void)rightMouseUp:(NSEvent *)event |
|||
{ |
|||
_isRightPressed = false; |
|||
[self mouseEvent:event withType:RightButtonUp]; |
|||
} |
|||
|
|||
- (void)mouseDragged:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Move]; |
|||
[super mouseDragged:event]; |
|||
} |
|||
|
|||
- (void)otherMouseDragged:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Move]; |
|||
[super otherMouseDragged:event]; |
|||
} |
|||
|
|||
- (void)rightMouseDragged:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Move]; |
|||
[super rightMouseDragged:event]; |
|||
} |
|||
|
|||
- (void)scrollWheel:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Wheel]; |
|||
[super scrollWheel:event]; |
|||
} |
|||
|
|||
- (void)magnifyWithEvent:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Magnify]; |
|||
[super magnifyWithEvent:event]; |
|||
} |
|||
|
|||
- (void)rotateWithEvent:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Rotate]; |
|||
[super rotateWithEvent:event]; |
|||
} |
|||
|
|||
- (void)swipeWithEvent:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:Swipe]; |
|||
[super swipeWithEvent:event]; |
|||
} |
|||
|
|||
- (void)mouseEntered:(NSEvent *)event |
|||
{ |
|||
[super mouseEntered:event]; |
|||
} |
|||
|
|||
- (void)mouseExited:(NSEvent *)event |
|||
{ |
|||
[self mouseEvent:event withType:LeaveWindow]; |
|||
[super mouseExited:event]; |
|||
} |
|||
|
|||
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type |
|||
{ |
|||
if([self ignoreUserInput: false]) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
auto key = s_KeyMap[[event keyCode]]; |
|||
|
|||
uint32_t timestamp = static_cast<uint32_t>([event timestamp] * 1000); |
|||
auto modifiers = [self getModifiers:[event modifierFlags]]; |
|||
|
|||
if(_parent != nullptr) |
|||
{ |
|||
_lastKeyHandled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key); |
|||
} |
|||
} |
|||
|
|||
- (BOOL)performKeyEquivalent:(NSEvent *)event |
|||
{ |
|||
bool result = _lastKeyHandled; |
|||
|
|||
_lastKeyHandled = false; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
- (void)flagsChanged:(NSEvent *)event |
|||
{ |
|||
auto newModifierState = [self getModifiers:[event modifierFlags]]; |
|||
|
|||
bool isAltCurrentlyPressed = (_modifierState & Alt) == Alt; |
|||
bool isControlCurrentlyPressed = (_modifierState & Control) == Control; |
|||
bool isShiftCurrentlyPressed = (_modifierState & Shift) == Shift; |
|||
bool isCommandCurrentlyPressed = (_modifierState & Windows) == Windows; |
|||
|
|||
bool isAltPressed = (newModifierState & Alt) == Alt; |
|||
bool isControlPressed = (newModifierState & Control) == Control; |
|||
bool isShiftPressed = (newModifierState & Shift) == Shift; |
|||
bool isCommandPressed = (newModifierState & Windows) == Windows; |
|||
|
|||
|
|||
if (isAltPressed && !isAltCurrentlyPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyDown]; |
|||
} |
|||
else if (isAltCurrentlyPressed && !isAltPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyUp]; |
|||
} |
|||
|
|||
if (isControlPressed && !isControlCurrentlyPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyDown]; |
|||
} |
|||
else if (isControlCurrentlyPressed && !isControlPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyUp]; |
|||
} |
|||
|
|||
if (isShiftPressed && !isShiftCurrentlyPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyDown]; |
|||
} |
|||
else if(isShiftCurrentlyPressed && !isShiftPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyUp]; |
|||
} |
|||
|
|||
if(isCommandPressed && !isCommandCurrentlyPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyDown]; |
|||
} |
|||
else if(isCommandCurrentlyPressed && ! isCommandPressed) |
|||
{ |
|||
[self keyboardEvent:event withType:KeyUp]; |
|||
} |
|||
|
|||
_modifierState = newModifierState; |
|||
|
|||
[[self inputContext] handleEvent:event]; |
|||
[super flagsChanged:event]; |
|||
} |
|||
|
|||
- (void)keyDown:(NSEvent *)event |
|||
{ |
|||
[self keyboardEvent:event withType:KeyDown]; |
|||
[[self inputContext] handleEvent:event]; |
|||
[super keyDown:event]; |
|||
} |
|||
|
|||
- (void)keyUp:(NSEvent *)event |
|||
{ |
|||
[self keyboardEvent:event withType:KeyUp]; |
|||
[super keyUp:event]; |
|||
} |
|||
|
|||
- (AvnInputModifiers)getModifiers:(NSEventModifierFlags)mod |
|||
{ |
|||
unsigned int rv = 0; |
|||
|
|||
if (mod & NSEventModifierFlagControl) |
|||
rv |= Control; |
|||
if (mod & NSEventModifierFlagShift) |
|||
rv |= Shift; |
|||
if (mod & NSEventModifierFlagOption) |
|||
rv |= Alt; |
|||
if (mod & NSEventModifierFlagCommand) |
|||
rv |= Windows; |
|||
|
|||
if (_isLeftPressed) |
|||
rv |= LeftMouseButton; |
|||
if (_isMiddlePressed) |
|||
rv |= MiddleMouseButton; |
|||
if (_isRightPressed) |
|||
rv |= RightMouseButton; |
|||
if (_isXButton1Pressed) |
|||
rv |= XButton1MouseButton; |
|||
if (_isXButton2Pressed) |
|||
rv |= XButton2MouseButton; |
|||
|
|||
return (AvnInputModifiers)rv; |
|||
} |
|||
|
|||
- (BOOL)hasMarkedText |
|||
{ |
|||
return _lastKeyHandled; |
|||
} |
|||
|
|||
- (NSRange)markedRange |
|||
{ |
|||
return NSMakeRange(NSNotFound, 0); |
|||
} |
|||
|
|||
- (NSRange)selectedRange |
|||
{ |
|||
return NSMakeRange(NSNotFound, 0); |
|||
} |
|||
|
|||
- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange |
|||
{ |
|||
|
|||
} |
|||
|
|||
- (void)unmarkText |
|||
{ |
|||
|
|||
} |
|||
|
|||
- (NSArray<NSString *> *)validAttributesForMarkedText |
|||
{ |
|||
return [NSArray new]; |
|||
} |
|||
|
|||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange |
|||
{ |
|||
return [NSAttributedString new]; |
|||
} |
|||
|
|||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange |
|||
{ |
|||
if(!_lastKeyHandled) |
|||
{ |
|||
if(_parent != nullptr) |
|||
{ |
|||
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(0, [string UTF8String]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
- (NSUInteger)characterIndexForPoint:(NSPoint)point |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange |
|||
{ |
|||
CGRect result = { 0 }; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
- (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id <NSDraggingInfo>)info |
|||
{ |
|||
auto localPoint = [self convertPoint:[info draggingLocation] toView:self]; |
|||
auto avnPoint = [AvnView toAvnPoint:localPoint]; |
|||
auto point = [self translateLocalPoint:avnPoint]; |
|||
auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]]; |
|||
NSDragOperation nsop = [info draggingSourceOperationMask]; |
|||
|
|||
auto effects = ConvertDragDropEffects(nsop); |
|||
int reffects = (int)_parent->BaseEvents |
|||
->DragEvent(type, point, modifiers, effects, |
|||
CreateClipboard([info draggingPasteboard], nil), |
|||
GetAvnDataObjectHandleFromDraggingInfo(info)); |
|||
|
|||
NSDragOperation ret = static_cast<NSDragOperation>(0); |
|||
|
|||
// Ensure that the managed part didn't add any new effects |
|||
reffects = (int)effects & reffects; |
|||
|
|||
// OSX requires exactly one operation |
|||
if((reffects & (int)AvnDragDropEffects::Copy) != 0) |
|||
ret = NSDragOperationCopy; |
|||
else if((reffects & (int)AvnDragDropEffects::Move) != 0) |
|||
ret = NSDragOperationMove; |
|||
else if((reffects & (int)AvnDragDropEffects::Link) != 0) |
|||
ret = NSDragOperationLink; |
|||
if(ret == 0) |
|||
ret = NSDragOperationNone; |
|||
return ret; |
|||
} |
|||
|
|||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender |
|||
{ |
|||
return [self triggerAvnDragEvent: AvnDragEventType::Enter info:sender]; |
|||
} |
|||
|
|||
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender |
|||
{ |
|||
return [self triggerAvnDragEvent: AvnDragEventType::Over info:sender]; |
|||
} |
|||
|
|||
- (void)draggingExited:(id <NSDraggingInfo>)sender |
|||
{ |
|||
[self triggerAvnDragEvent: AvnDragEventType::Leave info:sender]; |
|||
} |
|||
|
|||
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender |
|||
{ |
|||
return [self triggerAvnDragEvent: AvnDragEventType::Over info:sender] != NSDragOperationNone; |
|||
} |
|||
|
|||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender |
|||
{ |
|||
return [self triggerAvnDragEvent: AvnDragEventType::Drop info:sender] != NSDragOperationNone; |
|||
} |
|||
|
|||
- (void)concludeDragOperation:(nullable id <NSDraggingInfo>)sender |
|||
{ |
|||
|
|||
} |
|||
|
|||
- (AvnPlatformResizeReason)getResizeReason |
|||
{ |
|||
return _resizeReason; |
|||
} |
|||
|
|||
- (void)setResizeReason:(AvnPlatformResizeReason)reason |
|||
{ |
|||
_resizeReason = reason; |
|||
} |
|||
|
|||
- (AvnAccessibilityElement *) accessibilityChild |
|||
{ |
|||
if (_accessibilityChild == nil) |
|||
{ |
|||
auto peer = _parent->BaseEvents->GetAutomationPeer(); |
|||
|
|||
if (peer == nil) |
|||
return nil; |
|||
|
|||
_accessibilityChild = [AvnAccessibilityElement acquire:peer]; |
|||
} |
|||
|
|||
return _accessibilityChild; |
|||
} |
|||
|
|||
- (NSArray *)accessibilityChildren |
|||
{ |
|||
auto child = [self accessibilityChild]; |
|||
return NSAccessibilityUnignoredChildrenForOnlyChild(child); |
|||
} |
|||
|
|||
- (id)accessibilityHitTest:(NSPoint)point |
|||
{ |
|||
return [[self accessibilityChild] accessibilityHitTest:point]; |
|||
} |
|||
|
|||
- (id)accessibilityFocusedUIElement |
|||
{ |
|||
return [[self accessibilityChild] accessibilityFocusedUIElement]; |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,441 @@ |
|||
// |
|||
// Created by Dan Walmsley on 06/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#import "WindowProtocol.h" |
|||
#import "WindowBaseImpl.h" |
|||
|
|||
#ifdef IS_NSPANEL |
|||
#define BASE_CLASS NSPanel |
|||
#define CLASS_NAME AvnPanel |
|||
#else |
|||
#define BASE_CLASS NSWindow |
|||
#define CLASS_NAME AvnWindow |
|||
#endif |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#include "common.h" |
|||
#include "menu.h" |
|||
#include "automation.h" |
|||
#include "WindowBaseImpl.h" |
|||
#include "WindowImpl.h" |
|||
#include "AvnView.h" |
|||
#include "WindowInterfaces.h" |
|||
#include "PopupImpl.h" |
|||
|
|||
@implementation CLASS_NAME |
|||
{ |
|||
ComPtr<WindowBaseImpl> _parent; |
|||
bool _closed; |
|||
bool _isEnabled; |
|||
bool _isExtended; |
|||
AvnMenu* _menu; |
|||
} |
|||
|
|||
-(void) setIsExtended:(bool)value; |
|||
{ |
|||
_isExtended = value; |
|||
} |
|||
|
|||
-(bool) isDialog |
|||
{ |
|||
return _parent->IsDialog(); |
|||
} |
|||
|
|||
-(double) getExtendedTitleBarHeight |
|||
{ |
|||
if(_isExtended) |
|||
{ |
|||
for (id subview in self.contentView.superview.subviews) |
|||
{ |
|||
if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")]) |
|||
{ |
|||
NSView *titlebarView = [subview subviews][0]; |
|||
|
|||
return (double)titlebarView.frame.size.height; |
|||
} |
|||
} |
|||
|
|||
return -1; |
|||
} |
|||
else |
|||
{ |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
- (void)performClose:(id)sender |
|||
{ |
|||
if([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) |
|||
{ |
|||
if(![[self delegate] windowShouldClose:self]) return; |
|||
} |
|||
else if([self respondsToSelector:@selector(windowShouldClose:)]) |
|||
{ |
|||
if(![self windowShouldClose:self]) return; |
|||
} |
|||
|
|||
[self close]; |
|||
} |
|||
|
|||
- (void)pollModalSession:(nonnull NSModalSession)session |
|||
{ |
|||
auto response = [NSApp runModalSession:session]; |
|||
|
|||
if(response == NSModalResponseContinue) |
|||
{ |
|||
dispatch_async(dispatch_get_main_queue(), ^{ |
|||
[self pollModalSession:session]; |
|||
}); |
|||
} |
|||
else if (!_closed) |
|||
{ |
|||
[self orderOut:self]; |
|||
[NSApp endModalSession:session]; |
|||
} |
|||
} |
|||
|
|||
-(void) showWindowMenuWithAppMenu |
|||
{ |
|||
if(_menu != nullptr) |
|||
{ |
|||
auto appMenuItem = ::GetAppMenuItem(); |
|||
|
|||
if(appMenuItem != nullptr) |
|||
{ |
|||
auto appMenu = [appMenuItem menu]; |
|||
|
|||
[appMenu removeItem:appMenuItem]; |
|||
|
|||
[_menu insertItem:appMenuItem atIndex:0]; |
|||
|
|||
[_menu setHasGlobalMenuItem:true]; |
|||
} |
|||
|
|||
[NSApp setMenu:_menu]; |
|||
} |
|||
else |
|||
{ |
|||
[self showAppMenuOnly]; |
|||
} |
|||
} |
|||
|
|||
-(void) showAppMenuOnly |
|||
{ |
|||
auto appMenuItem = ::GetAppMenuItem(); |
|||
|
|||
if(appMenuItem != nullptr) |
|||
{ |
|||
auto appMenu = ::GetAppMenu(); |
|||
|
|||
auto nativeAppMenu = dynamic_cast<AvnAppMenu*>(appMenu); |
|||
|
|||
[[appMenuItem menu] removeItem:appMenuItem]; |
|||
|
|||
if(_menu != nullptr) |
|||
{ |
|||
[_menu setHasGlobalMenuItem:false]; |
|||
} |
|||
|
|||
[nativeAppMenu->GetNative() addItem:appMenuItem]; |
|||
|
|||
[NSApp setMenu:nativeAppMenu->GetNative()]; |
|||
} |
|||
} |
|||
|
|||
-(void) applyMenu:(AvnMenu *)menu |
|||
{ |
|||
if(menu == nullptr) |
|||
{ |
|||
menu = [AvnMenu new]; |
|||
} |
|||
|
|||
_menu = menu; |
|||
} |
|||
|
|||
-(CLASS_NAME*) initWithParent: (WindowBaseImpl*) 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 |
|||
// until several ms after the window is physically on the screen. |
|||
self = [super initWithContentRect:contentRect styleMask: styleMask backing:NSBackingStoreBuffered defer:false]; |
|||
|
|||
[self setReleasedWhenClosed:false]; |
|||
_parent = parent; |
|||
[self setDelegate:self]; |
|||
_closed = false; |
|||
_isEnabled = true; |
|||
|
|||
[self backingScaleFactor]; |
|||
[self setOpaque:NO]; |
|||
[self setBackgroundColor: [NSColor clearColor]]; |
|||
|
|||
_isExtended = false; |
|||
return self; |
|||
} |
|||
|
|||
- (BOOL)windowShouldClose:(NSWindow *)sender |
|||
{ |
|||
auto window = dynamic_cast<WindowImpl*>(_parent.getRaw()); |
|||
|
|||
if(window != nullptr) |
|||
{ |
|||
return !window->WindowEvents->Closing(); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification |
|||
{ |
|||
[self backingScaleFactor]; |
|||
} |
|||
|
|||
- (void)windowWillClose:(NSNotification *)notification |
|||
{ |
|||
_closed = true; |
|||
if(_parent) |
|||
{ |
|||
ComPtr<WindowBaseImpl> parent = _parent; |
|||
_parent = NULL; |
|||
[self restoreParentWindow]; |
|||
parent->BaseEvents->Closed(); |
|||
[parent->View onClosed]; |
|||
} |
|||
} |
|||
|
|||
-(BOOL)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 ch = static_cast<id <AvnWindowProtocol>>(uch); |
|||
if(ch == nil) |
|||
continue; |
|||
if (ch.isDialog) |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
-(BOOL)canBecomeMainWindow |
|||
{ |
|||
#ifdef IS_NSPANEL |
|||
return false; |
|||
#else |
|||
return true; |
|||
#endif |
|||
} |
|||
|
|||
-(bool)shouldTryToHandleEvents |
|||
{ |
|||
return _isEnabled; |
|||
} |
|||
|
|||
-(void) setEnabled:(bool)enable |
|||
{ |
|||
_isEnabled = enable; |
|||
} |
|||
|
|||
-(void)becomeKeyWindow |
|||
{ |
|||
[self showWindowMenuWithAppMenu]; |
|||
|
|||
if(_parent != nullptr) |
|||
{ |
|||
_parent->BaseEvents->Activated(); |
|||
} |
|||
|
|||
[super becomeKeyWindow]; |
|||
} |
|||
|
|||
-(void) restoreParentWindow; |
|||
{ |
|||
auto parent = [self parentWindow]; |
|||
|
|||
if(parent != nil) |
|||
{ |
|||
[parent removeChildWindow:self]; |
|||
} |
|||
} |
|||
|
|||
- (void)windowDidMiniaturize:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->WindowStateChanged(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowDidDeminiaturize:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->WindowStateChanged(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowDidResize:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->WindowStateChanged(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowWillExitFullScreen:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->StartStateTransition(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowDidExitFullScreen:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->EndStateTransition(); |
|||
|
|||
if(parent->Decorations() != SystemDecorationsFull && parent->WindowState() == Maximized) |
|||
{ |
|||
NSRect screenRect = [[self screen] visibleFrame]; |
|||
[self setFrame:screenRect display:YES]; |
|||
} |
|||
|
|||
if(parent->WindowState() == Minimized) |
|||
{ |
|||
[self miniaturize:nullptr]; |
|||
} |
|||
|
|||
parent->WindowStateChanged(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowWillEnterFullScreen:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->StartStateTransition(); |
|||
} |
|||
} |
|||
|
|||
- (void)windowDidEnterFullScreen:(NSNotification *)notification |
|||
{ |
|||
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->()); |
|||
|
|||
if(parent != nullptr) |
|||
{ |
|||
parent->EndStateTransition(); |
|||
parent->WindowStateChanged(); |
|||
} |
|||
} |
|||
|
|||
- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
-(void)resignKeyWindow |
|||
{ |
|||
if(_parent) |
|||
_parent->BaseEvents->Deactivated(); |
|||
|
|||
[self showAppMenuOnly]; |
|||
|
|||
[super resignKeyWindow]; |
|||
} |
|||
|
|||
- (void)windowDidMove:(NSNotification *)notification |
|||
{ |
|||
AvnPoint position; |
|||
|
|||
if(_parent != nullptr) |
|||
{ |
|||
auto cparent = dynamic_cast<WindowImpl*>(_parent.getRaw()); |
|||
|
|||
if(cparent != nullptr) |
|||
{ |
|||
if(cparent->WindowState() == Maximized) |
|||
{ |
|||
cparent->SetWindowState(Normal); |
|||
} |
|||
} |
|||
|
|||
_parent->GetPosition(&position); |
|||
_parent->BaseEvents->PositionChanged(position); |
|||
} |
|||
} |
|||
|
|||
- (AvnPoint) translateLocalPoint:(AvnPoint)pt |
|||
{ |
|||
pt.Y = [self frame].size.height - pt.Y; |
|||
return pt; |
|||
} |
|||
|
|||
- (void)sendEvent:(NSEvent *)event |
|||
{ |
|||
[super sendEvent:event]; |
|||
|
|||
/// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast. |
|||
if(_parent != nullptr && dynamic_cast<WindowImpl*>(_parent.getRaw()) != nullptr) |
|||
{ |
|||
switch(event.type) |
|||
{ |
|||
case NSEventTypeLeftMouseDown: |
|||
{ |
|||
AvnView* view = _parent->View; |
|||
NSPoint windowPoint = [event locationInWindow]; |
|||
NSPoint viewPoint = [view convertPoint:windowPoint fromView:nil]; |
|||
|
|||
if (!NSPointInRect(viewPoint, view.bounds)) |
|||
{ |
|||
auto avnPoint = [AvnView toAvnPoint:windowPoint]; |
|||
auto point = [self translateLocalPoint:avnPoint]; |
|||
AvnVector delta = { 0, 0 }; |
|||
|
|||
_parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint32>([event timestamp] * 1000), AvnInputModifiersNone, point, delta); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case NSEventTypeMouseEntered: |
|||
{ |
|||
_parent->UpdateCursor(); |
|||
} |
|||
break; |
|||
|
|||
case NSEventTypeMouseExited: |
|||
{ |
|||
[[NSCursor arrowCursor] set]; |
|||
} |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
- (void)disconnectParent { |
|||
_parent = nullptr; |
|||
} |
|||
|
|||
@end |
|||
|
|||
@ -0,0 +1,17 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 04/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H |
|||
#define AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H |
|||
|
|||
@class AvnView; |
|||
|
|||
struct INSWindowHolder |
|||
{ |
|||
virtual NSWindow* _Nonnull GetNSWindow () = 0; |
|||
virtual NSView* _Nonnull GetNSView () = 0; |
|||
}; |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H
|
|||
@ -0,0 +1,18 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 04/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H |
|||
#define AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H |
|||
|
|||
struct IWindowStateChanged |
|||
{ |
|||
virtual void WindowStateChanged () = 0; |
|||
virtual void StartStateTransition () = 0; |
|||
virtual void EndStateTransition () = 0; |
|||
virtual SystemDecorations Decorations () = 0; |
|||
virtual AvnWindowState WindowState () = 0; |
|||
}; |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_IWINDOWSTATECHANGED_H
|
|||
@ -0,0 +1,9 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 06/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_POPUPIMPL_H |
|||
#define AVALONIA_NATIVE_OSX_POPUPIMPL_H |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_POPUPIMPL_H
|
|||
@ -0,0 +1,68 @@ |
|||
// |
|||
// Created by Dan Walmsley on 06/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#include "WindowInterfaces.h" |
|||
#include "AvnView.h" |
|||
#include "WindowImpl.h" |
|||
#include "automation.h" |
|||
#include "menu.h" |
|||
#include "common.h" |
|||
#import "WindowBaseImpl.h" |
|||
#import "WindowProtocol.h" |
|||
#import <AppKit/AppKit.h> |
|||
#include "PopupImpl.h" |
|||
|
|||
class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup |
|||
{ |
|||
private: |
|||
BEGIN_INTERFACE_MAP() |
|||
INHERIT_INTERFACE_MAP(WindowBaseImpl) |
|||
INTERFACE_MAP_ENTRY(IAvnPopup, IID_IAvnPopup) |
|||
END_INTERFACE_MAP() |
|||
virtual ~PopupImpl(){} |
|||
ComPtr<IAvnWindowEvents> WindowEvents; |
|||
PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) |
|||
{ |
|||
WindowEvents = events; |
|||
[Window setLevel:NSPopUpMenuWindowLevel]; |
|||
} |
|||
protected: |
|||
virtual NSWindowStyleMask GetStyle() override |
|||
{ |
|||
return NSWindowStyleMaskBorderless; |
|||
} |
|||
|
|||
virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override |
|||
{ |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool |
|||
{ |
|||
if (Window != nullptr) |
|||
{ |
|||
[Window setContentSize:NSSize{x, y}]; |
|||
|
|||
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
public: |
|||
virtual bool ShouldTakeFocusOnShow() override |
|||
{ |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
|
|||
extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl) |
|||
{ |
|||
@autoreleasepool |
|||
{ |
|||
IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events, gl)); |
|||
return ptr; |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 04/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_RESIZESCOPE_H |
|||
#define AVALONIA_NATIVE_OSX_RESIZESCOPE_H |
|||
|
|||
#include "avalonia-native.h" |
|||
|
|||
@class AvnView; |
|||
|
|||
class ResizeScope |
|||
{ |
|||
public: |
|||
ResizeScope(AvnView* _Nonnull view, AvnPlatformResizeReason reason); |
|||
|
|||
~ResizeScope(); |
|||
private: |
|||
AvnView* _Nonnull _view; |
|||
AvnPlatformResizeReason _restore; |
|||
}; |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_RESIZESCOPE_H
|
|||
@ -0,0 +1,18 @@ |
|||
// |
|||
// Created by Dan Walmsley on 04/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#include "ResizeScope.h" |
|||
#include "AvnView.h" |
|||
|
|||
ResizeScope::ResizeScope(AvnView *view, AvnPlatformResizeReason reason) { |
|||
_view = view; |
|||
_restore = [view getResizeReason]; |
|||
[view setResizeReason:reason]; |
|||
} |
|||
|
|||
ResizeScope::~ResizeScope() { |
|||
[_view setResizeReason:_restore]; |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 04/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H |
|||
#define AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H |
|||
|
|||
#include "rendertarget.h" |
|||
#include "INSWindowHolder.h" |
|||
|
|||
@class AutoFitContentView; |
|||
@class AvnMenu; |
|||
@protocol AvnWindowProtocol; |
|||
|
|||
class WindowBaseImpl : public virtual ComObject, |
|||
public virtual IAvnWindowBase, |
|||
public INSWindowHolder { |
|||
private: |
|||
NSCursor *cursor; |
|||
|
|||
public: |
|||
FORWARD_IUNKNOWN() |
|||
|
|||
BEGIN_INTERFACE_MAP() |
|||
INTERFACE_MAP_ENTRY(IAvnWindowBase, IID_IAvnWindowBase) |
|||
END_INTERFACE_MAP() |
|||
|
|||
virtual ~WindowBaseImpl(); |
|||
|
|||
AutoFitContentView *StandardContainer; |
|||
AvnView *View; |
|||
NSWindow * Window; |
|||
ComPtr<IAvnWindowBaseEvents> BaseEvents; |
|||
ComPtr<IAvnGlContext> _glContext; |
|||
NSObject <IRenderTarget> *renderTarget; |
|||
AvnPoint lastPositionSet; |
|||
NSSize lastSize; |
|||
NSSize lastMinSize; |
|||
NSSize lastMaxSize; |
|||
AvnMenu* lastMenu; |
|||
NSString *_lastTitle; |
|||
|
|||
bool _shown; |
|||
bool _inResize; |
|||
|
|||
WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl); |
|||
|
|||
virtual HRESULT ObtainNSWindowHandle(void **ret) override; |
|||
|
|||
virtual HRESULT ObtainNSWindowHandleRetained(void **ret) override; |
|||
|
|||
virtual HRESULT ObtainNSViewHandle(void **ret) override; |
|||
|
|||
virtual HRESULT ObtainNSViewHandleRetained(void **ret) override; |
|||
|
|||
virtual NSWindow *GetNSWindow() override; |
|||
|
|||
virtual NSView *GetNSView() override; |
|||
|
|||
virtual HRESULT Show(bool activate, bool isDialog) override; |
|||
|
|||
virtual bool ShouldTakeFocusOnShow(); |
|||
|
|||
virtual HRESULT Hide() override; |
|||
|
|||
virtual HRESULT Activate() override; |
|||
|
|||
virtual HRESULT SetTopMost(bool value) override; |
|||
|
|||
virtual HRESULT Close() override; |
|||
|
|||
virtual HRESULT GetClientSize(AvnSize *ret) override; |
|||
|
|||
virtual HRESULT GetFrameSize(AvnSize *ret) override; |
|||
|
|||
virtual HRESULT GetScaling(double *ret) override; |
|||
|
|||
virtual HRESULT SetMinMaxSize(AvnSize minSize, AvnSize maxSize) override; |
|||
|
|||
virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override; |
|||
|
|||
virtual HRESULT Invalidate(__attribute__((unused)) AvnRect rect) override; |
|||
|
|||
virtual HRESULT SetMainMenu(IAvnMenu *menu) override; |
|||
|
|||
virtual HRESULT BeginMoveDrag() override; |
|||
|
|||
virtual HRESULT BeginResizeDrag(__attribute__((unused)) AvnWindowEdge edge) override; |
|||
|
|||
virtual HRESULT GetPosition(AvnPoint *ret) override; |
|||
|
|||
virtual HRESULT SetPosition(AvnPoint point) override; |
|||
|
|||
virtual HRESULT PointToClient(AvnPoint point, AvnPoint *ret) override; |
|||
|
|||
virtual HRESULT PointToScreen(AvnPoint point, AvnPoint *ret) override; |
|||
|
|||
virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer *fb, IUnknown *dispose) override; |
|||
|
|||
virtual HRESULT SetCursor(IAvnCursor *cursor) override; |
|||
|
|||
virtual void UpdateCursor(); |
|||
|
|||
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget **ppv) override; |
|||
|
|||
virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost **retOut) override; |
|||
|
|||
virtual HRESULT SetBlurEnabled(bool enable) override; |
|||
|
|||
virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, |
|||
IAvnClipboard *clipboard, IAvnDndResultCallback *cb, |
|||
void *sourceHandle) override; |
|||
|
|||
virtual bool IsDialog(); |
|||
|
|||
id<AvnWindowProtocol> GetWindowProtocol (); |
|||
|
|||
protected: |
|||
virtual NSWindowStyleMask GetStyle(); |
|||
|
|||
void UpdateStyle(); |
|||
|
|||
private: |
|||
void CreateNSWindow (bool isDialog); |
|||
void CleanNSWindow (); |
|||
void InitialiseNSWindow (); |
|||
}; |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H
|
|||
@ -0,0 +1,589 @@ |
|||
// |
|||
// Created by Dan Walmsley on 04/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#include "common.h" |
|||
#include "AvnView.h" |
|||
#include "menu.h" |
|||
#include "automation.h" |
|||
#include "cursor.h" |
|||
#include "ResizeScope.h" |
|||
#include "AutoFitContentView.h" |
|||
#import "WindowProtocol.h" |
|||
#import "WindowInterfaces.h" |
|||
#include "WindowBaseImpl.h" |
|||
|
|||
|
|||
WindowBaseImpl::~WindowBaseImpl() { |
|||
View = nullptr; |
|||
Window = nullptr; |
|||
} |
|||
|
|||
WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) { |
|||
_shown = false; |
|||
_inResize = false; |
|||
BaseEvents = events; |
|||
_glContext = gl; |
|||
renderTarget = [[IOSurfaceRenderTarget alloc] initWithOpenGlContext:gl]; |
|||
View = [[AvnView alloc] initWithParent:this]; |
|||
StandardContainer = [[AutoFitContentView new] initWithContent:View]; |
|||
|
|||
lastPositionSet.X = 100; |
|||
lastPositionSet.Y = 100; |
|||
lastSize = NSSize { 100, 100 }; |
|||
lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX}; |
|||
lastMinSize = NSSize { 0, 0 }; |
|||
_lastTitle = @""; |
|||
|
|||
Window = nullptr; |
|||
lastMenu = nullptr; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge void *) View; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::ObtainNSViewHandleRetained(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge_retained void *) View; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
NSWindow *WindowBaseImpl::GetNSWindow() { |
|||
return Window; |
|||
} |
|||
|
|||
NSView *WindowBaseImpl::GetNSView() { |
|||
return View; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::ObtainNSWindowHandleRetained(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge_retained void *) Window; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
CreateNSWindow(isDialog); |
|||
InitialiseNSWindow(); |
|||
|
|||
SetPosition(lastPositionSet); |
|||
UpdateStyle(); |
|||
|
|||
[Window setTitle:_lastTitle]; |
|||
|
|||
if (ShouldTakeFocusOnShow() && activate) { |
|||
[Window orderFront:Window]; |
|||
[Window makeKeyAndOrderFront:Window]; |
|||
[Window makeFirstResponder:View]; |
|||
[NSApp activateIgnoringOtherApps:YES]; |
|||
} else { |
|||
[Window orderFront:Window]; |
|||
} |
|||
|
|||
_shown = true; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
bool WindowBaseImpl::ShouldTakeFocusOnShow() { |
|||
return true; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::ObtainNSWindowHandle(void **ret) { |
|||
START_COM_CALL; |
|||
|
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = (__bridge void *) Window; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Hide() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (Window != nullptr) { |
|||
[Window orderOut:Window]; |
|||
|
|||
[GetWindowProtocol() restoreParentWindow]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Activate() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (Window != nullptr) { |
|||
[Window makeKeyAndOrderFront:nil]; |
|||
[NSApp activateIgnoringOtherApps:YES]; |
|||
} |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetTopMost(bool value) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
[Window setLevel:value ? NSFloatingWindowLevel : NSNormalWindowLevel]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Close() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (Window != nullptr) { |
|||
auto window = Window; |
|||
Window = nullptr; |
|||
|
|||
try { |
|||
// Seems to throw sometimes on application exit. |
|||
[window close]; |
|||
} |
|||
catch (NSException *) {} |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::GetClientSize(AvnSize *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) |
|||
return E_POINTER; |
|||
|
|||
auto frame = [View frame]; |
|||
ret->Width = frame.size.width; |
|||
ret->Height = frame.size.height; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::GetFrameSize(AvnSize *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) |
|||
return E_POINTER; |
|||
|
|||
auto frame = [Window frame]; |
|||
ret->Width = frame.size.width; |
|||
ret->Height = frame.size.height; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::GetScaling(double *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) |
|||
return E_POINTER; |
|||
|
|||
if (Window == nullptr) { |
|||
*ret = 1; |
|||
return S_OK; |
|||
} |
|||
|
|||
*ret = [Window backingScaleFactor]; |
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetMinMaxSize(AvnSize minSize, AvnSize maxSize) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
lastMinSize = ToNSSize(minSize); |
|||
lastMaxSize = ToNSSize(maxSize); |
|||
|
|||
if(Window != nullptr) { |
|||
[Window setContentMinSize:lastMinSize]; |
|||
[Window setContentMaxSize:lastMaxSize]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reason) { |
|||
if (_inResize) { |
|||
return S_OK; |
|||
} |
|||
|
|||
_inResize = true; |
|||
|
|||
START_COM_CALL; |
|||
auto resizeBlock = ResizeScope(View, reason); |
|||
|
|||
@autoreleasepool { |
|||
auto maxSize = lastMaxSize; |
|||
auto minSize = lastMinSize; |
|||
|
|||
if (x < minSize.width) { |
|||
x = minSize.width; |
|||
} |
|||
|
|||
if (y < minSize.height) { |
|||
y = minSize.height; |
|||
} |
|||
|
|||
if (x > maxSize.width) { |
|||
x = maxSize.width; |
|||
} |
|||
|
|||
if (y > maxSize.height) { |
|||
y = maxSize.height; |
|||
} |
|||
|
|||
@try { |
|||
if (!_shown) { |
|||
BaseEvents->Resized(AvnSize{x, y}, reason); |
|||
} |
|||
|
|||
lastSize = NSSize {x, y}; |
|||
|
|||
if(Window != nullptr) { |
|||
[Window setContentSize:lastSize]; |
|||
} |
|||
} |
|||
@finally { |
|||
_inResize = false; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::Invalidate(__attribute__((unused)) AvnRect rect) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
[View setNeedsDisplayInRect:[View frame]]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetMainMenu(IAvnMenu *menu) { |
|||
START_COM_CALL; |
|||
|
|||
auto nativeMenu = dynamic_cast<AvnAppMenu *>(menu); |
|||
|
|||
lastMenu = nativeMenu->GetNative(); |
|||
|
|||
if(Window != nullptr) { |
|||
[GetWindowProtocol() applyMenu:lastMenu]; |
|||
|
|||
if ([Window isKeyWindow]) { |
|||
[GetWindowProtocol() showWindowMenuWithAppMenu]; |
|||
} |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::BeginMoveDrag() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
auto lastEvent = [View lastMouseDownEvent]; |
|||
|
|||
if (lastEvent == nullptr) { |
|||
return S_OK; |
|||
} |
|||
|
|||
[Window performWindowDragWithEvent:lastEvent]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::BeginResizeDrag(__attribute__((unused)) AvnWindowEdge edge) { |
|||
START_COM_CALL; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::GetPosition(AvnPoint *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
auto frame = [Window frame]; |
|||
|
|||
ret->X = frame.origin.x; |
|||
ret->Y = frame.origin.y + frame.size.height; |
|||
|
|||
*ret = ConvertPointY(*ret); |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetPosition(AvnPoint point) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
lastPositionSet = point; |
|||
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(point))]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::PointToClient(AvnPoint point, AvnPoint *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
point = ConvertPointY(point); |
|||
NSRect convertRect = [Window convertRectFromScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; |
|||
auto viewPoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); |
|||
|
|||
*ret = [View translateLocalPoint:ToAvnPoint(viewPoint)]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::PointToScreen(AvnPoint point, AvnPoint *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]); |
|||
NSRect convertRect = [Window convertRectToScreen:NSMakeRect(cocoaViewPoint.x, cocoaViewPoint.y, 0.0, 0.0)]; |
|||
auto cocoaScreenPoint = NSPointFromCGPoint(NSMakePoint(convertRect.origin.x, convertRect.origin.y)); |
|||
*ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint)); |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::ThreadSafeSetSwRenderedFrame(AvnFramebuffer *fb, IUnknown *dispose) { |
|||
START_COM_CALL; |
|||
|
|||
[View setSwRenderedFrame:fb dispose:dispose]; |
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetCursor(IAvnCursor *cursor) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
Cursor *avnCursor = dynamic_cast<Cursor *>(cursor); |
|||
this->cursor = avnCursor->GetNative(); |
|||
UpdateCursor(); |
|||
|
|||
if (avnCursor->IsHidden()) { |
|||
[NSCursor hide]; |
|||
} else { |
|||
[NSCursor unhide]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
void WindowBaseImpl::UpdateCursor() { |
|||
if (cursor != nil) { |
|||
[cursor set]; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::CreateGlRenderTarget(IAvnGlSurfaceRenderTarget **ppv) { |
|||
START_COM_CALL; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
*ppv = [renderTarget createSurfaceRenderTarget]; |
|||
return static_cast<HRESULT>(*ppv == nil ? E_FAIL : S_OK); |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::CreateNativeControlHost(IAvnNativeControlHost **retOut) { |
|||
START_COM_CALL; |
|||
|
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
*retOut = ::CreateNativeControlHost(View); |
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::SetBlurEnabled(bool enable) { |
|||
START_COM_CALL; |
|||
|
|||
[StandardContainer ShowBlur:enable]; |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowBaseImpl::BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point, IAvnClipboard *clipboard, IAvnDndResultCallback *cb, void *sourceHandle) { |
|||
START_COM_CALL; |
|||
|
|||
auto item = TryGetPasteboardItem(clipboard); |
|||
[item setString:@"" forType:GetAvnCustomDataType()]; |
|||
if (item == nil) |
|||
return E_INVALIDARG; |
|||
if (View == NULL) |
|||
return E_FAIL; |
|||
|
|||
auto nsevent = [NSApp currentEvent]; |
|||
auto nseventType = [nsevent type]; |
|||
|
|||
// If current event isn't a mouse one (probably due to malfunctioning user app) |
|||
// attempt to forge a new one |
|||
if (!((nseventType >= NSEventTypeLeftMouseDown && nseventType <= NSEventTypeMouseExited) |
|||
|| (nseventType >= NSEventTypeOtherMouseDown && nseventType <= NSEventTypeOtherMouseDragged))) { |
|||
NSRect convertRect = [Window convertRectToScreen:NSMakeRect(point.X, point.Y, 0.0, 0.0)]; |
|||
auto nspoint = NSMakePoint(convertRect.origin.x, convertRect.origin.y); |
|||
CGPoint cgpoint = NSPointToCGPoint(nspoint); |
|||
auto cgevent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, cgpoint, kCGMouseButtonLeft); |
|||
nsevent = [NSEvent eventWithCGEvent:cgevent]; |
|||
CFRelease(cgevent); |
|||
} |
|||
|
|||
auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:item]; |
|||
|
|||
auto dragItemImage = [NSImage imageNamed:NSImageNameMultipleDocuments]; |
|||
NSRect dragItemRect = {(float) point.X, (float) point.Y, [dragItemImage size].width, [dragItemImage size].height}; |
|||
[dragItem setDraggingFrame:dragItemRect contents:dragItemImage]; |
|||
|
|||
int op = 0; |
|||
int ieffects = (int) effects; |
|||
if ((ieffects & (int) AvnDragDropEffects::Copy) != 0) |
|||
op |= NSDragOperationCopy; |
|||
if ((ieffects & (int) AvnDragDropEffects::Link) != 0) |
|||
op |= NSDragOperationLink; |
|||
if ((ieffects & (int) AvnDragDropEffects::Move) != 0) |
|||
op |= NSDragOperationMove; |
|||
[View beginDraggingSessionWithItems:@[dragItem] event:nsevent |
|||
source:CreateDraggingSource((NSDragOperation) op, cb, sourceHandle)]; |
|||
return S_OK; |
|||
} |
|||
|
|||
bool WindowBaseImpl::IsDialog() { |
|||
return false; |
|||
} |
|||
|
|||
NSWindowStyleMask WindowBaseImpl::GetStyle() { |
|||
return NSWindowStyleMaskBorderless; |
|||
} |
|||
|
|||
void WindowBaseImpl::UpdateStyle() { |
|||
[Window setStyleMask:GetStyle()]; |
|||
} |
|||
|
|||
void WindowBaseImpl::CleanNSWindow() { |
|||
if(Window != nullptr) { |
|||
[GetWindowProtocol() disconnectParent]; |
|||
[Window close]; |
|||
Window = nullptr; |
|||
} |
|||
} |
|||
|
|||
void WindowBaseImpl::CreateNSWindow(bool isDialog) { |
|||
if (isDialog) { |
|||
if (![Window isKindOfClass:[AvnPanel class]]) { |
|||
CleanNSWindow(); |
|||
|
|||
Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()]; |
|||
} |
|||
} else { |
|||
if (![Window isKindOfClass:[AvnWindow class]]) { |
|||
CleanNSWindow(); |
|||
|
|||
Window = [[AvnWindow alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void WindowBaseImpl::InitialiseNSWindow() { |
|||
if(Window != nullptr) { |
|||
[Window setContentView:StandardContainer]; |
|||
[Window setStyleMask:NSWindowStyleMaskBorderless]; |
|||
[Window setBackingType:NSBackingStoreBuffered]; |
|||
|
|||
[Window setContentSize:lastSize]; |
|||
[Window setContentMinSize:lastMinSize]; |
|||
[Window setContentMaxSize:lastMaxSize]; |
|||
|
|||
[Window setOpaque:false]; |
|||
|
|||
if (lastMenu != nullptr) { |
|||
[GetWindowProtocol() applyMenu:lastMenu]; |
|||
|
|||
if ([Window isKeyWindow]) { |
|||
[GetWindowProtocol() showWindowMenuWithAppMenu]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
id <AvnWindowProtocol> WindowBaseImpl::GetWindowProtocol() { |
|||
if(Window == nullptr) |
|||
{ |
|||
return nullptr; |
|||
} |
|||
|
|||
return static_cast<id <AvnWindowProtocol>>(Window); |
|||
} |
|||
|
|||
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl) |
|||
{ |
|||
@autoreleasepool |
|||
{ |
|||
IAvnWindow* ptr = (IAvnWindow*)new WindowImpl(events, gl); |
|||
return ptr; |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 04/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#ifndef AVALONIA_NATIVE_OSX_WINDOWIMPL_H |
|||
#define AVALONIA_NATIVE_OSX_WINDOWIMPL_H |
|||
|
|||
#import "WindowBaseImpl.h" |
|||
#include "IWindowStateChanged.h" |
|||
|
|||
class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged |
|||
{ |
|||
private: |
|||
bool _canResize; |
|||
bool _fullScreenActive; |
|||
SystemDecorations _decorations; |
|||
AvnWindowState _lastWindowState; |
|||
AvnWindowState _actualWindowState; |
|||
bool _inSetWindowState; |
|||
NSRect _preZoomSize; |
|||
bool _transitioningWindowState; |
|||
bool _isClientAreaExtended; |
|||
bool _isDialog; |
|||
AvnExtendClientAreaChromeHints _extendClientHints; |
|||
|
|||
FORWARD_IUNKNOWN() |
|||
BEGIN_INTERFACE_MAP() |
|||
INHERIT_INTERFACE_MAP(WindowBaseImpl) |
|||
INTERFACE_MAP_ENTRY(IAvnWindow, IID_IAvnWindow) |
|||
END_INTERFACE_MAP() |
|||
virtual ~WindowImpl() |
|||
{ |
|||
} |
|||
|
|||
ComPtr<IAvnWindowEvents> WindowEvents; |
|||
|
|||
WindowImpl(IAvnWindowEvents* events, IAvnGlContext* gl); |
|||
|
|||
void HideOrShowTrafficLights (); |
|||
|
|||
virtual HRESULT Show (bool activate, bool isDialog) override; |
|||
|
|||
virtual HRESULT SetEnabled (bool enable) override; |
|||
|
|||
virtual HRESULT SetParent (IAvnWindow* parent) override; |
|||
|
|||
void StartStateTransition () override ; |
|||
|
|||
void EndStateTransition () override ; |
|||
|
|||
SystemDecorations Decorations () override ; |
|||
|
|||
AvnWindowState WindowState () override ; |
|||
|
|||
void WindowStateChanged () override ; |
|||
|
|||
bool UndecoratedIsMaximized (); |
|||
|
|||
bool IsZoomed (); |
|||
|
|||
void DoZoom(); |
|||
|
|||
virtual HRESULT SetCanResize(bool value) override; |
|||
|
|||
virtual HRESULT SetDecorations(SystemDecorations value) override; |
|||
|
|||
virtual HRESULT SetTitle (char* utf8title) override; |
|||
|
|||
virtual HRESULT SetTitleBarColor(AvnColor color) override; |
|||
|
|||
virtual HRESULT GetWindowState (AvnWindowState*ret) override; |
|||
|
|||
virtual HRESULT TakeFocusFromChildren () override; |
|||
|
|||
virtual HRESULT SetExtendClientArea (bool enable) override; |
|||
|
|||
virtual HRESULT SetExtendClientAreaHints (AvnExtendClientAreaChromeHints hints) override; |
|||
|
|||
virtual HRESULT GetExtendTitleBarHeight (double*ret) override; |
|||
|
|||
virtual HRESULT SetExtendTitleBarHeight (double value) override; |
|||
|
|||
void EnterFullScreenMode (); |
|||
|
|||
void ExitFullScreenMode (); |
|||
|
|||
virtual HRESULT SetWindowState (AvnWindowState state) override; |
|||
|
|||
virtual bool IsDialog() override; |
|||
|
|||
protected: |
|||
virtual NSWindowStyleMask GetStyle() override; |
|||
}; |
|||
|
|||
#endif //AVALONIA_NATIVE_OSX_WINDOWIMPL_H
|
|||
@ -0,0 +1,552 @@ |
|||
// |
|||
// Created by Dan Walmsley on 04/05/2022. |
|||
// Copyright (c) 2022 Avalonia. All rights reserved. |
|||
// |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
#include "AutoFitContentView.h" |
|||
#include "AvnView.h" |
|||
#include "automation.h" |
|||
#include "WindowProtocol.h" |
|||
|
|||
WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) { |
|||
_isClientAreaExtended = false; |
|||
_extendClientHints = AvnDefaultChrome; |
|||
_fullScreenActive = false; |
|||
_canResize = true; |
|||
_decorations = SystemDecorationsFull; |
|||
_transitioningWindowState = false; |
|||
_inSetWindowState = false; |
|||
_lastWindowState = Normal; |
|||
_actualWindowState = Normal; |
|||
WindowEvents = events; |
|||
[Window disableCursorRects]; |
|||
[Window setTabbingMode:NSWindowTabbingModeDisallowed]; |
|||
[Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; |
|||
} |
|||
|
|||
void WindowImpl::HideOrShowTrafficLights() { |
|||
if (Window == nil) { |
|||
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]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::Show(bool activate, bool isDialog) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
_isDialog = isDialog; |
|||
|
|||
bool created = Window == nullptr; |
|||
|
|||
WindowBaseImpl::Show(activate, isDialog); |
|||
|
|||
if(created) |
|||
{ |
|||
if(_isClientAreaExtended) |
|||
{ |
|||
[GetWindowProtocol() setIsExtended:true]; |
|||
SetExtendClientArea(true); |
|||
} |
|||
} |
|||
|
|||
HideOrShowTrafficLights(); |
|||
|
|||
return SetWindowState(_lastWindowState); |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetEnabled(bool enable) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
[GetWindowProtocol() setEnabled:enable]; |
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetParent(IAvnWindow *parent) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (parent == nullptr) |
|||
return E_POINTER; |
|||
|
|||
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); |
|||
|
|||
[Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; |
|||
[cparent->Window addChildWindow:Window ordered:NSWindowAbove]; |
|||
|
|||
UpdateStyle(); |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
void WindowImpl::StartStateTransition() { |
|||
_transitioningWindowState = true; |
|||
} |
|||
|
|||
void WindowImpl::EndStateTransition() { |
|||
_transitioningWindowState = false; |
|||
} |
|||
|
|||
SystemDecorations WindowImpl::Decorations() { |
|||
return _decorations; |
|||
} |
|||
|
|||
AvnWindowState WindowImpl::WindowState() { |
|||
return _lastWindowState; |
|||
} |
|||
|
|||
void WindowImpl::WindowStateChanged() { |
|||
if (_shown && !_inSetWindowState && !_transitioningWindowState) { |
|||
AvnWindowState state; |
|||
GetWindowState(&state); |
|||
|
|||
if (_lastWindowState != state) { |
|||
if (_isClientAreaExtended) { |
|||
if (_lastWindowState == FullScreen) { |
|||
// we exited fs. |
|||
if (_extendClientHints & AvnOSXThickTitleBar) { |
|||
Window.toolbar = [NSToolbar new]; |
|||
Window.toolbar.showsBaselineSeparator = false; |
|||
} |
|||
|
|||
[Window setTitlebarAppearsTransparent:true]; |
|||
|
|||
[StandardContainer setFrameSize:StandardContainer.frame.size]; |
|||
} else if (state == FullScreen) { |
|||
// we entered fs. |
|||
if (_extendClientHints & AvnOSXThickTitleBar) { |
|||
Window.toolbar = nullptr; |
|||
} |
|||
|
|||
[Window setTitlebarAppearsTransparent:false]; |
|||
|
|||
[StandardContainer setFrameSize:StandardContainer.frame.size]; |
|||
} |
|||
} |
|||
|
|||
_lastWindowState = state; |
|||
_actualWindowState = state; |
|||
WindowEvents->WindowStateChanged(state); |
|||
} |
|||
} |
|||
} |
|||
|
|||
bool WindowImpl::UndecoratedIsMaximized() { |
|||
auto windowSize = [Window frame]; |
|||
auto available = [Window screen].visibleFrame; |
|||
return CGRectEqualToRect(windowSize, available); |
|||
} |
|||
|
|||
bool WindowImpl::IsZoomed() { |
|||
return _decorations == SystemDecorationsFull ? [Window isZoomed] : UndecoratedIsMaximized(); |
|||
} |
|||
|
|||
void WindowImpl::DoZoom() { |
|||
switch (_decorations) { |
|||
case SystemDecorationsNone: |
|||
case SystemDecorationsBorderOnly: |
|||
[Window setFrame:[Window screen].visibleFrame display:true]; |
|||
break; |
|||
|
|||
|
|||
case SystemDecorationsFull: |
|||
[Window performZoom:Window]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetCanResize(bool value) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
_canResize = value; |
|||
UpdateStyle(); |
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetDecorations(SystemDecorations value) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
auto currentWindowState = _lastWindowState; |
|||
_decorations = value; |
|||
|
|||
if (_fullScreenActive) { |
|||
return S_OK; |
|||
} |
|||
|
|||
UpdateStyle(); |
|||
|
|||
HideOrShowTrafficLights(); |
|||
|
|||
switch (_decorations) { |
|||
case SystemDecorationsNone: |
|||
[Window setHasShadow:NO]; |
|||
[Window setTitleVisibility:NSWindowTitleHidden]; |
|||
[Window setTitlebarAppearsTransparent:YES]; |
|||
|
|||
if (currentWindowState == Maximized) { |
|||
if (!UndecoratedIsMaximized()) { |
|||
DoZoom(); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case SystemDecorationsBorderOnly: |
|||
[Window setHasShadow:YES]; |
|||
[Window setTitleVisibility:NSWindowTitleHidden]; |
|||
[Window setTitlebarAppearsTransparent:YES]; |
|||
|
|||
if (currentWindowState == Maximized) { |
|||
if (!UndecoratedIsMaximized()) { |
|||
DoZoom(); |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case SystemDecorationsFull: |
|||
[Window setHasShadow:YES]; |
|||
[Window setTitleVisibility:NSWindowTitleVisible]; |
|||
[Window setTitlebarAppearsTransparent:NO]; |
|||
[Window setTitle:_lastTitle]; |
|||
|
|||
if (currentWindowState == Maximized) { |
|||
auto newFrame = [Window contentRectForFrameRect:[Window frame]].size; |
|||
|
|||
[View setFrameSize:newFrame]; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetTitle(char *utf8title) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
_lastTitle = [NSString stringWithUTF8String:(const char *) utf8title]; |
|||
[Window setTitle:_lastTitle]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetTitleBarColor(AvnColor color) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
float a = (float) color.Alpha / 255.0f; |
|||
float r = (float) color.Red / 255.0f; |
|||
float g = (float) color.Green / 255.0f; |
|||
float b = (float) color.Blue / 255.0f; |
|||
|
|||
auto nscolor = [NSColor colorWithSRGBRed:r green:g blue:b alpha:a]; |
|||
|
|||
// Based on the titlebar color we have to choose either light or dark |
|||
// OSX doesnt let you set a foreground color for titlebar. |
|||
if ((r * 0.299 + g * 0.587 + b * 0.114) > 186.0f / 255.0f) { |
|||
[Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]]; |
|||
} else { |
|||
[Window setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]]; |
|||
} |
|||
|
|||
[Window setTitlebarAppearsTransparent:true]; |
|||
[Window setBackgroundColor:nscolor]; |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
|
|||
HRESULT WindowImpl::GetWindowState(AvnWindowState *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
if (([Window styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) { |
|||
*ret = FullScreen; |
|||
return S_OK; |
|||
} |
|||
|
|||
if ([Window isMiniaturized]) { |
|||
*ret = Minimized; |
|||
return S_OK; |
|||
} |
|||
|
|||
if (IsZoomed()) { |
|||
*ret = Maximized; |
|||
return S_OK; |
|||
} |
|||
|
|||
*ret = Normal; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::TakeFocusFromChildren() { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (Window == nil) |
|||
return S_OK; |
|||
if ([Window isKeyWindow]) |
|||
[Window makeFirstResponder:View]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetExtendClientArea(bool enable) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
_isClientAreaExtended = enable; |
|||
|
|||
if(Window != nullptr) { |
|||
if (enable) { |
|||
Window.titleVisibility = NSWindowTitleHidden; |
|||
|
|||
[Window setTitlebarAppearsTransparent:true]; |
|||
|
|||
auto wantsTitleBar = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); |
|||
|
|||
if (wantsTitleBar) { |
|||
[StandardContainer ShowTitleBar:true]; |
|||
} else { |
|||
[StandardContainer ShowTitleBar:false]; |
|||
} |
|||
|
|||
if (_extendClientHints & AvnOSXThickTitleBar) { |
|||
Window.toolbar = [NSToolbar new]; |
|||
Window.toolbar.showsBaselineSeparator = false; |
|||
} else { |
|||
Window.toolbar = nullptr; |
|||
} |
|||
} else { |
|||
Window.titleVisibility = NSWindowTitleVisible; |
|||
Window.toolbar = nullptr; |
|||
[Window setTitlebarAppearsTransparent:false]; |
|||
View.layer.zPosition = 0; |
|||
} |
|||
|
|||
[GetWindowProtocol() setIsExtended:enable]; |
|||
|
|||
HideOrShowTrafficLights(); |
|||
|
|||
UpdateStyle(); |
|||
} |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetExtendClientAreaHints(AvnExtendClientAreaChromeHints hints) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
_extendClientHints = hints; |
|||
|
|||
SetExtendClientArea(_isClientAreaExtended); |
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::GetExtendTitleBarHeight(double *ret) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (ret == nullptr) { |
|||
return E_POINTER; |
|||
} |
|||
|
|||
*ret = [GetWindowProtocol() getExtendedTitleBarHeight]; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetExtendTitleBarHeight(double value) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
[StandardContainer SetTitleBarHeightHint:value]; |
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
void WindowImpl::EnterFullScreenMode() { |
|||
_fullScreenActive = true; |
|||
|
|||
[Window setTitle:_lastTitle]; |
|||
[Window toggleFullScreen:nullptr]; |
|||
} |
|||
|
|||
void WindowImpl::ExitFullScreenMode() { |
|||
[Window toggleFullScreen:nullptr]; |
|||
|
|||
_fullScreenActive = false; |
|||
|
|||
SetDecorations(_decorations); |
|||
} |
|||
|
|||
HRESULT WindowImpl::SetWindowState(AvnWindowState state) { |
|||
START_COM_CALL; |
|||
|
|||
@autoreleasepool { |
|||
if (Window == nullptr) { |
|||
return S_OK; |
|||
} |
|||
|
|||
if (_actualWindowState == state) { |
|||
return S_OK; |
|||
} |
|||
|
|||
_inSetWindowState = true; |
|||
|
|||
auto currentState = _actualWindowState; |
|||
_lastWindowState = state; |
|||
|
|||
if (currentState == Normal) { |
|||
_preZoomSize = [Window frame]; |
|||
} |
|||
|
|||
if (_shown) { |
|||
switch (state) { |
|||
case Maximized: |
|||
if (currentState == FullScreen) { |
|||
ExitFullScreenMode(); |
|||
} |
|||
|
|||
lastPositionSet.X = 0; |
|||
lastPositionSet.Y = 0; |
|||
|
|||
if ([Window isMiniaturized]) { |
|||
[Window deminiaturize:Window]; |
|||
} |
|||
|
|||
if (!IsZoomed()) { |
|||
DoZoom(); |
|||
} |
|||
break; |
|||
|
|||
case Minimized: |
|||
if (currentState == FullScreen) { |
|||
ExitFullScreenMode(); |
|||
} else { |
|||
[Window miniaturize:Window]; |
|||
} |
|||
break; |
|||
|
|||
case FullScreen: |
|||
if ([Window isMiniaturized]) { |
|||
[Window deminiaturize:Window]; |
|||
} |
|||
|
|||
EnterFullScreenMode(); |
|||
break; |
|||
|
|||
case Normal: |
|||
if ([Window isMiniaturized]) { |
|||
[Window deminiaturize:Window]; |
|||
} |
|||
|
|||
if (currentState == FullScreen) { |
|||
ExitFullScreenMode(); |
|||
} |
|||
|
|||
if (IsZoomed()) { |
|||
if (_decorations == SystemDecorationsFull) { |
|||
DoZoom(); |
|||
} else { |
|||
[Window setFrame:_preZoomSize display:true]; |
|||
auto newFrame = [Window contentRectForFrameRect:[Window frame]].size; |
|||
|
|||
[View setFrameSize:newFrame]; |
|||
} |
|||
|
|||
} |
|||
break; |
|||
} |
|||
|
|||
_actualWindowState = _lastWindowState; |
|||
WindowEvents->WindowStateChanged(_actualWindowState); |
|||
} |
|||
|
|||
|
|||
_inSetWindowState = false; |
|||
|
|||
return S_OK; |
|||
} |
|||
} |
|||
|
|||
bool WindowImpl::IsDialog() { |
|||
return _isDialog; |
|||
} |
|||
|
|||
NSWindowStyleMask WindowImpl::GetStyle() { |
|||
unsigned long s = this->_isDialog ? NSWindowStyleMaskUtilityWindow : NSWindowStyleMaskBorderless; |
|||
|
|||
switch (_decorations) { |
|||
case SystemDecorationsNone: |
|||
s = s | NSWindowStyleMaskFullSizeContentView; |
|||
break; |
|||
|
|||
case SystemDecorationsBorderOnly: |
|||
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskFullSizeContentView; |
|||
break; |
|||
|
|||
case SystemDecorationsFull: |
|||
s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskBorderless; |
|||
|
|||
if (_canResize) { |
|||
s = s | NSWindowStyleMaskResizable; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
if ([Window parentWindow] == nullptr) { |
|||
s |= NSWindowStyleMaskMiniaturizable; |
|||
} |
|||
|
|||
if (_isClientAreaExtended) { |
|||
s |= NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskTexturedBackground; |
|||
} |
|||
return s; |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 06/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#import <Foundation/Foundation.h> |
|||
#import <AppKit/AppKit.h> |
|||
#include "WindowProtocol.h" |
|||
#include "WindowBaseImpl.h" |
|||
|
|||
@interface AvnWindow : NSWindow <AvnWindowProtocol, NSWindowDelegate> |
|||
-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; |
|||
@end |
|||
|
|||
@interface AvnPanel : NSPanel <AvnWindowProtocol, NSWindowDelegate> |
|||
-(AvnPanel* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; |
|||
@end |
|||
@ -0,0 +1,25 @@ |
|||
//
|
|||
// Created by Dan Walmsley on 06/05/2022.
|
|||
// Copyright (c) 2022 Avalonia. All rights reserved.
|
|||
//
|
|||
|
|||
#pragma once |
|||
|
|||
#import <AppKit/AppKit.h> |
|||
|
|||
@class AvnMenu; |
|||
|
|||
@protocol AvnWindowProtocol |
|||
-(void) pollModalSession: (NSModalSession _Nonnull) session; |
|||
-(void) restoreParentWindow; |
|||
-(bool) shouldTryToHandleEvents; |
|||
-(void) setEnabled: (bool) enable; |
|||
-(void) showAppMenuOnly; |
|||
-(void) showWindowMenuWithAppMenu; |
|||
-(void) applyMenu:(AvnMenu* _Nullable)menu; |
|||
|
|||
-(double) getExtendedTitleBarHeight; |
|||
-(void) setIsExtended:(bool)value; |
|||
-(void) disconnectParent; |
|||
-(bool) isDialog; |
|||
@end |
|||
@ -0,0 +1,12 @@ |
|||
#pragma once |
|||
|
|||
#import <Cocoa/Cocoa.h> |
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
class IAvnAutomationPeer; |
|||
|
|||
@interface AvnAccessibilityElement : NSAccessibilityElement |
|||
+ (AvnAccessibilityElement *) acquire:(IAvnAutomationPeer *) peer; |
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,497 @@ |
|||
#include "common.h" |
|||
#include "automation.h" |
|||
#include "AvnString.h" |
|||
#include "INSWindowHolder.h" |
|||
#include "AvnView.h" |
|||
|
|||
@interface AvnAccessibilityElement (Events) |
|||
- (void) raiseChildrenChanged; |
|||
@end |
|||
|
|||
@interface AvnRootAccessibilityElement : AvnAccessibilityElement |
|||
- (AvnView *) ownerView; |
|||
- (AvnRootAccessibilityElement *) initWithPeer:(IAvnAutomationPeer *) peer owner:(AvnView*) owner; |
|||
- (void) raiseFocusChanged; |
|||
@end |
|||
|
|||
class AutomationNode : public ComSingleObject<IAvnAutomationNode, &IID_IAvnAutomationNode> |
|||
{ |
|||
public: |
|||
FORWARD_IUNKNOWN() |
|||
|
|||
AutomationNode(AvnAccessibilityElement* owner) |
|||
{ |
|||
_owner = owner; |
|||
} |
|||
|
|||
AvnAccessibilityElement* GetOwner() |
|||
{ |
|||
return _owner; |
|||
} |
|||
|
|||
virtual void Dispose() override |
|||
{ |
|||
_owner = nil; |
|||
} |
|||
|
|||
virtual void ChildrenChanged () override |
|||
{ |
|||
[_owner raiseChildrenChanged]; |
|||
} |
|||
|
|||
virtual void PropertyChanged (AvnAutomationProperty property) override |
|||
{ |
|||
|
|||
} |
|||
|
|||
virtual void FocusChanged () override |
|||
{ |
|||
[(AvnRootAccessibilityElement*)_owner raiseFocusChanged]; |
|||
} |
|||
|
|||
private: |
|||
__strong AvnAccessibilityElement* _owner; |
|||
}; |
|||
|
|||
@implementation AvnAccessibilityElement |
|||
{ |
|||
IAvnAutomationPeer* _peer; |
|||
AutomationNode* _node; |
|||
NSMutableArray* _children; |
|||
} |
|||
|
|||
+ (AvnAccessibilityElement *)acquire:(IAvnAutomationPeer *)peer |
|||
{ |
|||
if (peer == nullptr) |
|||
return nil; |
|||
|
|||
auto instance = peer->GetNode(); |
|||
|
|||
if (instance != nullptr) |
|||
return dynamic_cast<AutomationNode*>(instance)->GetOwner(); |
|||
|
|||
if (peer->IsRootProvider()) |
|||
{ |
|||
auto window = peer->RootProvider_GetWindow(); |
|||
auto holder = dynamic_cast<INSWindowHolder*>(window); |
|||
auto view = holder->GetNSView(); |
|||
return [[AvnRootAccessibilityElement alloc] initWithPeer:peer owner:view]; |
|||
} |
|||
else |
|||
{ |
|||
return [[AvnAccessibilityElement alloc] initWithPeer:peer]; |
|||
} |
|||
} |
|||
|
|||
- (AvnAccessibilityElement *)initWithPeer:(IAvnAutomationPeer *)peer |
|||
{ |
|||
self = [super init]; |
|||
_peer = peer; |
|||
_node = new AutomationNode(self); |
|||
_peer->SetNode(_node); |
|||
return self; |
|||
} |
|||
|
|||
- (void)dealloc |
|||
{ |
|||
if (_node) |
|||
delete _node; |
|||
_node = nullptr; |
|||
} |
|||
|
|||
- (NSString *)description |
|||
{ |
|||
return [NSString stringWithFormat:@"%@ '%@' (%p)", |
|||
GetNSStringAndRelease(_peer->GetClassName()), |
|||
GetNSStringAndRelease(_peer->GetName()), |
|||
_peer]; |
|||
} |
|||
|
|||
- (IAvnAutomationPeer *)peer |
|||
{ |
|||
return _peer; |
|||
} |
|||
|
|||
- (BOOL)isAccessibilityElement |
|||
{ |
|||
return _peer->IsControlElement(); |
|||
} |
|||
|
|||
- (NSAccessibilityRole)accessibilityRole |
|||
{ |
|||
auto controlType = _peer->GetAutomationControlType(); |
|||
|
|||
switch (controlType) { |
|||
case AutomationButton: return NSAccessibilityButtonRole; |
|||
case AutomationCalendar: return NSAccessibilityGridRole; |
|||
case AutomationCheckBox: return NSAccessibilityCheckBoxRole; |
|||
case AutomationComboBox: return NSAccessibilityPopUpButtonRole; |
|||
case AutomationComboBoxItem: return NSAccessibilityMenuItemRole; |
|||
case AutomationEdit: return NSAccessibilityTextFieldRole; |
|||
case AutomationHyperlink: return NSAccessibilityLinkRole; |
|||
case AutomationImage: return NSAccessibilityImageRole; |
|||
case AutomationListItem: return NSAccessibilityRowRole; |
|||
case AutomationList: return NSAccessibilityTableRole; |
|||
case AutomationMenu: return NSAccessibilityMenuBarRole; |
|||
case AutomationMenuBar: return NSAccessibilityMenuBarRole; |
|||
case AutomationMenuItem: return NSAccessibilityMenuItemRole; |
|||
case AutomationProgressBar: return NSAccessibilityProgressIndicatorRole; |
|||
case AutomationRadioButton: return NSAccessibilityRadioButtonRole; |
|||
case AutomationScrollBar: return NSAccessibilityScrollBarRole; |
|||
case AutomationSlider: return NSAccessibilitySliderRole; |
|||
case AutomationSpinner: return NSAccessibilityIncrementorRole; |
|||
case AutomationStatusBar: return NSAccessibilityTableRole; |
|||
case AutomationTab: return NSAccessibilityTabGroupRole; |
|||
case AutomationTabItem: return NSAccessibilityRadioButtonRole; |
|||
case AutomationText: return NSAccessibilityStaticTextRole; |
|||
case AutomationToolBar: return NSAccessibilityToolbarRole; |
|||
case AutomationToolTip: return NSAccessibilityPopoverRole; |
|||
case AutomationTree: return NSAccessibilityOutlineRole; |
|||
case AutomationTreeItem: return NSAccessibilityCellRole; |
|||
case AutomationCustom: return NSAccessibilityUnknownRole; |
|||
case AutomationGroup: return NSAccessibilityGroupRole; |
|||
case AutomationThumb: return NSAccessibilityHandleRole; |
|||
case AutomationDataGrid: return NSAccessibilityGridRole; |
|||
case AutomationDataItem: return NSAccessibilityCellRole; |
|||
case AutomationDocument: return NSAccessibilityStaticTextRole; |
|||
case AutomationSplitButton: return NSAccessibilityPopUpButtonRole; |
|||
case AutomationWindow: return NSAccessibilityWindowRole; |
|||
case AutomationPane: return NSAccessibilityGroupRole; |
|||
case AutomationHeader: return NSAccessibilityGroupRole; |
|||
case AutomationHeaderItem: return NSAccessibilityButtonRole; |
|||
case AutomationTable: return NSAccessibilityTableRole; |
|||
case AutomationTitleBar: return NSAccessibilityGroupRole; |
|||
// Treat unknown roles as generic group container items. Returning |
|||
// NSAccessibilityUnknownRole is also possible but makes the screen |
|||
// reader focus on the item instead of passing focus to child items. |
|||
default: return NSAccessibilityGroupRole; |
|||
} |
|||
} |
|||
|
|||
- (NSString *)accessibilityIdentifier |
|||
{ |
|||
return GetNSStringAndRelease(_peer->GetAutomationId()); |
|||
} |
|||
|
|||
- (NSString *)accessibilityTitle |
|||
{ |
|||
// StaticText exposes its text via the value property. |
|||
if (_peer->GetAutomationControlType() != AutomationText) |
|||
{ |
|||
return GetNSStringAndRelease(_peer->GetName()); |
|||
} |
|||
|
|||
return [super accessibilityTitle]; |
|||
} |
|||
|
|||
- (id)accessibilityValue |
|||
{ |
|||
if (_peer->IsRangeValueProvider()) |
|||
{ |
|||
return [NSNumber numberWithDouble:_peer->RangeValueProvider_GetValue()]; |
|||
} |
|||
else if (_peer->IsToggleProvider()) |
|||
{ |
|||
switch (_peer->ToggleProvider_GetToggleState()) { |
|||
case 0: return [NSNumber numberWithBool:NO]; |
|||
case 1: return [NSNumber numberWithBool:YES]; |
|||
default: return [NSNumber numberWithInt:2]; |
|||
} |
|||
} |
|||
else if (_peer->IsValueProvider()) |
|||
{ |
|||
return GetNSStringAndRelease(_peer->ValueProvider_GetValue()); |
|||
} |
|||
else if (_peer->GetAutomationControlType() == AutomationText) |
|||
{ |
|||
return GetNSStringAndRelease(_peer->GetName()); |
|||
} |
|||
|
|||
return [super accessibilityValue]; |
|||
} |
|||
|
|||
- (id)accessibilityMinValue |
|||
{ |
|||
if (_peer->IsRangeValueProvider()) |
|||
{ |
|||
return [NSNumber numberWithDouble:_peer->RangeValueProvider_GetMinimum()]; |
|||
} |
|||
|
|||
return [super accessibilityMinValue]; |
|||
} |
|||
|
|||
- (id)accessibilityMaxValue |
|||
{ |
|||
if (_peer->IsRangeValueProvider()) |
|||
{ |
|||
return [NSNumber numberWithDouble:_peer->RangeValueProvider_GetMaximum()]; |
|||
} |
|||
|
|||
return [super accessibilityMaxValue]; |
|||
} |
|||
|
|||
- (BOOL)isAccessibilityEnabled |
|||
{ |
|||
return _peer->IsEnabled(); |
|||
} |
|||
|
|||
- (BOOL)isAccessibilityFocused |
|||
{ |
|||
return _peer->HasKeyboardFocus(); |
|||
} |
|||
|
|||
- (NSArray *)accessibilityChildren |
|||
{ |
|||
if (_children == nullptr && _peer != nullptr) |
|||
[self recalculateChildren]; |
|||
return _children; |
|||
} |
|||
|
|||
- (NSRect)accessibilityFrame |
|||
{ |
|||
id topLevel = [self accessibilityTopLevelUIElement]; |
|||
auto result = NSZeroRect; |
|||
|
|||
if ([topLevel isKindOfClass:[AvnRootAccessibilityElement class]]) |
|||
{ |
|||
auto root = (AvnRootAccessibilityElement*)topLevel; |
|||
auto view = [root ownerView]; |
|||
|
|||
if (view) |
|||
{ |
|||
auto window = [view window]; |
|||
auto bounds = ToNSRect(_peer->GetBoundingRectangle()); |
|||
auto windowBounds = [view convertRect:bounds toView:nil]; |
|||
auto screenBounds = [window convertRectToScreen:windowBounds]; |
|||
result = screenBounds; |
|||
} |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
- (id)accessibilityParent |
|||
{ |
|||
auto parentPeer = _peer->GetParent(); |
|||
return parentPeer ? [AvnAccessibilityElement acquire:parentPeer] : [NSApplication sharedApplication]; |
|||
} |
|||
|
|||
- (id)accessibilityTopLevelUIElement |
|||
{ |
|||
auto rootPeer = _peer->GetRootPeer(); |
|||
return [AvnAccessibilityElement acquire:rootPeer]; |
|||
} |
|||
|
|||
- (id)accessibilityWindow |
|||
{ |
|||
id topLevel = [self accessibilityTopLevelUIElement]; |
|||
return [topLevel isKindOfClass:[NSWindow class]] ? topLevel : nil; |
|||
} |
|||
|
|||
- (BOOL)isAccessibilityExpanded |
|||
{ |
|||
if (!_peer->IsExpandCollapseProvider()) |
|||
return NO; |
|||
return _peer->ExpandCollapseProvider_GetIsExpanded(); |
|||
} |
|||
|
|||
- (void)setAccessibilityExpanded:(BOOL)accessibilityExpanded |
|||
{ |
|||
if (!_peer->IsExpandCollapseProvider()) |
|||
return; |
|||
if (accessibilityExpanded) |
|||
_peer->ExpandCollapseProvider_Expand(); |
|||
else |
|||
_peer->ExpandCollapseProvider_Collapse(); |
|||
} |
|||
|
|||
- (BOOL)accessibilityPerformPress |
|||
{ |
|||
if (_peer->IsInvokeProvider()) |
|||
{ |
|||
_peer->InvokeProvider_Invoke(); |
|||
} |
|||
else if (_peer->IsExpandCollapseProvider()) |
|||
{ |
|||
_peer->ExpandCollapseProvider_Expand(); |
|||
} |
|||
else if (_peer->IsToggleProvider()) |
|||
{ |
|||
_peer->ToggleProvider_Toggle(); |
|||
} |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)accessibilityPerformIncrement |
|||
{ |
|||
if (!_peer->IsRangeValueProvider()) |
|||
return NO; |
|||
auto value = _peer->RangeValueProvider_GetValue(); |
|||
value += _peer->RangeValueProvider_GetSmallChange(); |
|||
_peer->RangeValueProvider_SetValue(value); |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)accessibilityPerformDecrement |
|||
{ |
|||
if (!_peer->IsRangeValueProvider()) |
|||
return NO; |
|||
auto value = _peer->RangeValueProvider_GetValue(); |
|||
value -= _peer->RangeValueProvider_GetSmallChange(); |
|||
_peer->RangeValueProvider_SetValue(value); |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)accessibilityPerformShowMenu |
|||
{ |
|||
if (!_peer->IsExpandCollapseProvider()) |
|||
return NO; |
|||
_peer->ExpandCollapseProvider_Expand(); |
|||
return YES; |
|||
} |
|||
|
|||
- (BOOL)isAccessibilitySelected |
|||
{ |
|||
if (_peer->IsSelectionItemProvider()) |
|||
return _peer->SelectionItemProvider_IsSelected(); |
|||
return NO; |
|||
} |
|||
|
|||
- (BOOL)isAccessibilitySelectorAllowed:(SEL)selector |
|||
{ |
|||
if (selector == @selector(accessibilityPerformShowMenu)) |
|||
{ |
|||
return _peer->IsExpandCollapseProvider() && _peer->ExpandCollapseProvider_GetShowsMenu(); |
|||
} |
|||
else if (selector == @selector(isAccessibilityExpanded)) |
|||
{ |
|||
return _peer->IsExpandCollapseProvider(); |
|||
} |
|||
else if (selector == @selector(accessibilityPerformPress)) |
|||
{ |
|||
return _peer->IsInvokeProvider() || _peer->IsExpandCollapseProvider() || _peer->IsToggleProvider(); |
|||
} |
|||
else if (selector == @selector(accessibilityPerformIncrement) || |
|||
selector == @selector(accessibilityPerformDecrement) || |
|||
selector == @selector(accessibilityMinValue) || |
|||
selector == @selector(accessibilityMaxValue)) |
|||
{ |
|||
return _peer->IsRangeValueProvider(); |
|||
} |
|||
|
|||
return [super isAccessibilitySelectorAllowed:selector]; |
|||
} |
|||
|
|||
- (void)raiseChildrenChanged |
|||
{ |
|||
auto changed = _children ? [NSMutableSet setWithArray:_children] : [NSMutableSet set]; |
|||
|
|||
[self recalculateChildren]; |
|||
|
|||
if (_children) |
|||
[changed addObjectsFromArray:_children]; |
|||
|
|||
NSAccessibilityPostNotificationWithUserInfo( |
|||
self, |
|||
NSAccessibilityLayoutChangedNotification, |
|||
@{ NSAccessibilityUIElementsKey: [changed allObjects]}); |
|||
} |
|||
|
|||
- (void)raisePropertyChanged |
|||
{ |
|||
} |
|||
|
|||
- (void)setAccessibilityFocused:(BOOL)accessibilityFocused |
|||
{ |
|||
if (accessibilityFocused) |
|||
_peer->SetFocus(); |
|||
} |
|||
|
|||
- (void)recalculateChildren |
|||
{ |
|||
auto childPeers = _peer->GetChildren(); |
|||
auto childCount = childPeers != nullptr ? childPeers->GetCount() : 0; |
|||
|
|||
if (childCount > 0) |
|||
{ |
|||
_children = [[NSMutableArray alloc] initWithCapacity:childCount]; |
|||
|
|||
for (int i = 0; i < childCount; ++i) |
|||
{ |
|||
IAvnAutomationPeer* child; |
|||
|
|||
if (childPeers->Get(i, &child) == S_OK) |
|||
{ |
|||
auto element = [AvnAccessibilityElement acquire:child]; |
|||
[_children addObject:element]; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
_children = nil; |
|||
} |
|||
} |
|||
|
|||
@end |
|||
|
|||
@implementation AvnRootAccessibilityElement |
|||
{ |
|||
AvnView* _owner; |
|||
} |
|||
|
|||
- (AvnRootAccessibilityElement *)initWithPeer:(IAvnAutomationPeer *)peer owner:(AvnView *)owner |
|||
{ |
|||
self = [super initWithPeer:peer]; |
|||
_owner = owner; |
|||
|
|||
// Seems we need to raise a focus changed notification here if we have focus |
|||
auto focusedPeer = [self peer]->RootProvider_GetFocus(); |
|||
id focused = [AvnAccessibilityElement acquire:focusedPeer]; |
|||
|
|||
if (focused) |
|||
NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification); |
|||
|
|||
return self; |
|||
} |
|||
|
|||
- (AvnView *)ownerView |
|||
{ |
|||
return _owner; |
|||
} |
|||
|
|||
- (id)accessibilityFocusedUIElement |
|||
{ |
|||
auto focusedPeer = [self peer]->RootProvider_GetFocus(); |
|||
return [AvnAccessibilityElement acquire:focusedPeer]; |
|||
} |
|||
|
|||
- (id)accessibilityHitTest:(NSPoint)point |
|||
{ |
|||
auto clientPoint = [[_owner window] convertPointFromScreen:point]; |
|||
auto localPoint = [_owner translateLocalPoint:ToAvnPoint(clientPoint)]; |
|||
auto hit = [self peer]->RootProvider_GetPeerFromPoint(localPoint); |
|||
return [AvnAccessibilityElement acquire:hit]; |
|||
} |
|||
|
|||
- (id)accessibilityParent |
|||
{ |
|||
return _owner; |
|||
} |
|||
|
|||
- (void)raiseFocusChanged |
|||
{ |
|||
id focused = [self accessibilityFocusedUIElement]; |
|||
NSAccessibilityPostNotification(focused, NSAccessibilityFocusedUIElementChangedNotification); |
|||
} |
|||
|
|||
// Although this method is marked as deprecated we get runtime warnings if we don't handle it. |
|||
#pragma clang diagnostic push |
|||
#pragma clang diagnostic ignored "-Wdeprecated-implementations" |
|||
- (void)accessibilityPerformAction:(NSAccessibilityActionName)action |
|||
{ |
|||
[_owner accessibilityPerformAction:action]; |
|||
} |
|||
#pragma clang diagnostic pop |
|||
|
|||
@end |
|||
@ -1,76 +0,0 @@ |
|||
#ifndef window_h |
|||
#define window_h |
|||
|
|||
class WindowBaseImpl; |
|||
|
|||
@interface AvnView : NSView<NSTextInputClient, NSDraggingDestination> |
|||
-(AvnView* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent; |
|||
-(NSEvent* _Nonnull) lastMouseDownEvent; |
|||
-(AvnPoint) translateLocalPoint:(AvnPoint)pt; |
|||
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose; |
|||
-(void) onClosed; |
|||
-(AvnPixelSize) getPixelSize; |
|||
-(AvnPlatformResizeReason) getResizeReason; |
|||
-(void) setResizeReason:(AvnPlatformResizeReason)reason; |
|||
+ (AvnPoint)toAvnPoint:(CGPoint)p; |
|||
@end |
|||
|
|||
@interface AutoFitContentView : NSView |
|||
-(AutoFitContentView* _Nonnull) initWithContent: (NSView* _Nonnull) content; |
|||
-(void) ShowTitleBar: (bool) show; |
|||
-(void) SetTitleBarHeightHint: (double) height; |
|||
-(void) SetContent: (NSView* _Nonnull) content; |
|||
-(void) ShowBlur: (bool) show; |
|||
@end |
|||
|
|||
@interface AvnWindow : NSWindow <NSWindowDelegate> |
|||
+(void) closeAll; |
|||
-(AvnWindow* _Nonnull) initWithParent: (WindowBaseImpl* _Nonnull) parent; |
|||
-(void) setCanBecomeKeyAndMain; |
|||
-(void) pollModalSession: (NSModalSession _Nonnull) session; |
|||
-(void) restoreParentWindow; |
|||
-(bool) shouldTryToHandleEvents; |
|||
-(void) setEnabled: (bool) enable; |
|||
-(void) showAppMenuOnly; |
|||
-(void) showWindowMenuWithAppMenu; |
|||
-(void) applyMenu:(NSMenu* _Nullable)menu; |
|||
-(double) getScaling; |
|||
-(double) getExtendedTitleBarHeight; |
|||
-(void) setIsExtended:(bool)value; |
|||
-(bool) isDialog; |
|||
@end |
|||
|
|||
struct INSWindowHolder |
|||
{ |
|||
virtual AvnWindow* _Nonnull GetNSWindow () = 0; |
|||
}; |
|||
|
|||
struct IWindowStateChanged |
|||
{ |
|||
virtual void WindowStateChanged () = 0; |
|||
virtual void StartStateTransition () = 0; |
|||
virtual void EndStateTransition () = 0; |
|||
virtual SystemDecorations Decorations () = 0; |
|||
virtual AvnWindowState WindowState () = 0; |
|||
}; |
|||
|
|||
class ResizeScope |
|||
{ |
|||
public: |
|||
ResizeScope(AvnView* _Nonnull view, AvnPlatformResizeReason reason) |
|||
{ |
|||
_view = view; |
|||
_restore = [view getResizeReason]; |
|||
[view setResizeReason:reason]; |
|||
} |
|||
|
|||
~ResizeScope() |
|||
{ |
|||
[_view setResizeReason:_restore]; |
|||
} |
|||
private: |
|||
AvnView* _Nonnull _view; |
|||
AvnPlatformResizeReason _restore; |
|||
}; |
|||
|
|||
#endif /* window_h */ |
|||
File diff suppressed because it is too large
@ -1,19 +0,0 @@ |
|||
Any raw assets you want to be deployed with your application can be placed in |
|||
this directory (and child directories) and given a Build Action of "AndroidAsset". |
|||
|
|||
These files will be deployed with your package and will be accessible using Android's |
|||
AssetManager, like this: |
|||
|
|||
public class ReadAsset : Activity |
|||
{ |
|||
protected override void OnCreate (Bundle bundle) |
|||
{ |
|||
base.OnCreate (bundle); |
|||
|
|||
InputStream input = Assets.Open ("my_asset.txt"); |
|||
} |
|||
} |
|||
|
|||
Additionally, some Android functions will automatically load asset files: |
|||
|
|||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); |
|||
@ -1,165 +1,47 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProductVersion>8.0.30703</ProductVersion> |
|||
<SchemaVersion>2.0</SchemaVersion> |
|||
<ProjectGuid>{29132311-1848-4FD6-AE0C-4FF841151BD3}</ProjectGuid> |
|||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
|||
<OutputType>Library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>ControlCatalog.Android</RootNamespace> |
|||
<AssemblyName>ControlCatalog.Android</AssemblyName> |
|||
<FileAlignment>512</FileAlignment> |
|||
<AndroidApplication>true</AndroidApplication> |
|||
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile> |
|||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> |
|||
<AndroidUseLatestPlatformSdk>False</AndroidUseLatestPlatformSdk> |
|||
<TargetFrameworkVersion>v11.0</TargetFrameworkVersion> |
|||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest> |
|||
<TargetFramework>net6.0-android</TargetFramework> |
|||
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> |
|||
<OutputType>Exe</OutputType> |
|||
<Nullable>enable</Nullable> |
|||
<ApplicationId>com.Avalonia.ControlCatalog</ApplicationId> |
|||
<ApplicationVersion>1</ApplicationVersion> |
|||
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> |
|||
<AndroidPackageFormat>apk</AndroidPackageFormat> |
|||
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>True</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime> |
|||
<AndroidLinkMode>None</AndroidLinkMode> |
|||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk> |
|||
<BundleAssemblies>False</BundleAssemblies> |
|||
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi> |
|||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64</AndroidSupportedAbis> |
|||
<Debugger>Xamarin</Debugger> |
|||
<AndroidEnableMultiDex>False</AndroidEnableMultiDex> |
|||
<AotAssemblies>False</AotAssemblies> |
|||
<EnableLLVM>False</EnableLLVM> |
|||
<EnableProguard>False</EnableProguard> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime> |
|||
<AndroidLinkMode>Full</AndroidLinkMode> |
|||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk> |
|||
<BundleAssemblies>False</BundleAssemblies> |
|||
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi> |
|||
<AndroidSupportedAbis>armeabi-v7a,x86;x86_64</AndroidSupportedAbis> |
|||
<Debugger>Xamarin</Debugger> |
|||
<AotAssemblies>False</AotAssemblies> |
|||
<EnableLLVM>False</EnableLLVM> |
|||
<AndroidEnableMultiDex>False</AndroidEnableMultiDex> |
|||
<EnableProguard>False</EnableProguard> |
|||
<DebugSymbols>False</DebugSymbols> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="Mono.Android" /> |
|||
<Reference Include="mscorlib" /> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Xml.Linq" /> |
|||
<Reference Include="System.Xml" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="MainActivity.cs" /> |
|||
<Compile Include="Resources\Resource.Designer.cs" /> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
<Compile Include="SplashActivity.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<None Include="Resources\AboutResources.txt" /> |
|||
<None Include="Assets\AboutAssets.txt" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<AndroidResource Include="Resources\drawable\splash_screen.xml" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<AndroidResource Include="Resources\values\colors.xml" /> |
|||
<AndroidResource Include="Resources\values\styles.xml" /> |
|||
<None Remove="Assets\AboutAssets.txt" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<AndroidResource Include="..\..\build\Assets\Icon.png"> |
|||
<Link>Resources\drawable\Icon.png</Link> |
|||
</AndroidResource> |
|||
</ItemGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)'=='Release' and '$(TF_BUILD)' == ''"> |
|||
<DebugSymbols>True</DebugSymbols> |
|||
<RunAOTCompilation>True</RunAOTCompilation> |
|||
<EnableLLVM>True</EnableLLVM> |
|||
<AndroidEnableProfiledAot>True</AndroidEnableProfiledAot> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|||
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk> |
|||
<RunAOTCompilation>False</RunAOTCompilation> |
|||
</PropertyGroup> |
|||
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> |
|||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<None Include="Properties\AndroidManifest.xml" /> |
|||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.1.3" /> |
|||
<PackageReference Include="Xamarin.AndroidX.Lifecycle.ViewModel" Version="2.3.1.3" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj"> |
|||
<Project>{7B92AF71-6287-4693-9DCB-BD5B6E927E23}</Project> |
|||
<Name>Avalonia.Android</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj"> |
|||
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project> |
|||
<Name>Avalonia.Animation</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj"> |
|||
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project> |
|||
<Name>Avalonia.Base</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj"> |
|||
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project> |
|||
<Name>Avalonia.Controls</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj"> |
|||
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project> |
|||
<Name>Avalonia.Diagnostics</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj"> |
|||
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project> |
|||
<Name>Avalonia.Input</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj"> |
|||
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project> |
|||
<Name>Avalonia.Interactivity</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj"> |
|||
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project> |
|||
<Name>Avalonia.Layout</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj"> |
|||
<Project>{c42d2fc1-a531-4ed4-84b9-89aec7c962fc}</Project> |
|||
<Name>Avalonia.Themes.Fluent</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj"> |
|||
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project> |
|||
<Name>Avalonia.Visuals</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj"> |
|||
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project> |
|||
<Name>Avalonia.Styling</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj"> |
|||
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project> |
|||
<Name>Avalonia.Themes.Default</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj"> |
|||
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project> |
|||
<Name>Avalonia.Markup.Xaml</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj"> |
|||
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project> |
|||
<Name>Avalonia.Markup</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj"> |
|||
<Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project> |
|||
<Name>Avalonia.Skia</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj"> |
|||
<Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project> |
|||
<Name>ControlCatalog</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" /> |
|||
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> |
|||
</ItemGroup> |
|||
<Import Project="..\..\build\Rx.props" /> |
|||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" /> |
|||
<Import Project="..\..\build\AndroidWorkarounds.props" /> |
|||
<Import Project="..\..\build\LegacyProject.targets" /> |
|||
</Project> |
|||
</Project> |
|||
@ -1,5 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ControlCatalog.Android" android:versionCode="1" android:versionName="1.0" android:installLocation="auto"> |
|||
<uses-sdk android:targetSdkVersion="30" /> |
|||
<application android:label="ControlCatalog.Android"></application> |
|||
</manifest> |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> |
|||
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> |
|||
</manifest> |
|||
|
|||
@ -1,30 +0,0 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using Android.App; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle("ControlCatalog.Android")] |
|||
[assembly: AssemblyDescription("")] |
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("ControlCatalog.Android")] |
|||
[assembly: AssemblyCopyright("Copyright © 2016")] |
|||
[assembly: AssemblyTrademark("")] |
|||
[assembly: AssemblyCulture("")] |
|||
[assembly: ComVisible(false)] |
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion("1.0.0.0")] |
|||
[assembly: AssemblyFileVersion("1.0.0.0")] |
|||
@ -1,101 +0,0 @@ |
|||
#pragma warning disable 1591
|
|||
//------------------------------------------------------------------------------
|
|||
// <auto-generated>
|
|||
// This code was generated by a tool.
|
|||
//
|
|||
// Changes to this file may cause incorrect behavior and will be lost if
|
|||
// the code is regenerated.
|
|||
// </auto-generated>
|
|||
//------------------------------------------------------------------------------
|
|||
|
|||
[assembly: global::Android.Runtime.ResourceDesignerAttribute("ControlCatalog.Android.Resource", IsApplication=true)] |
|||
|
|||
namespace ControlCatalog.Android |
|||
{ |
|||
|
|||
|
|||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")] |
|||
public partial class Resource |
|||
{ |
|||
|
|||
static Resource() |
|||
{ |
|||
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); |
|||
} |
|||
|
|||
public static void UpdateIdValues() |
|||
{ |
|||
} |
|||
|
|||
public partial class Attribute |
|||
{ |
|||
|
|||
static Attribute() |
|||
{ |
|||
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); |
|||
} |
|||
|
|||
private Attribute() |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public partial class Color |
|||
{ |
|||
|
|||
// aapt resource value: 0x7F010000
|
|||
public const int splash_background = 2130771968; |
|||
|
|||
static Color() |
|||
{ |
|||
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); |
|||
} |
|||
|
|||
private Color() |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public partial class Drawable |
|||
{ |
|||
|
|||
// aapt resource value: 0x7F020000
|
|||
public const int Icon = 2130837504; |
|||
|
|||
// aapt resource value: 0x7F020001
|
|||
public const int splash_screen = 2130837505; |
|||
|
|||
static Drawable() |
|||
{ |
|||
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); |
|||
} |
|||
|
|||
private Drawable() |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public partial class Style |
|||
{ |
|||
|
|||
// aapt resource value: 0x7F030000
|
|||
public const int MyTheme = 2130903040; |
|||
|
|||
// aapt resource value: 0x7F030001
|
|||
public const int MyTheme_NoActionBar = 2130903041; |
|||
|
|||
// aapt resource value: 0x7F030002
|
|||
public const int MyTheme_Splash = 2130903042; |
|||
|
|||
static Style() |
|||
{ |
|||
global::Android.Runtime.ResourceIdManager.UpdateIdValues(); |
|||
} |
|||
|
|||
private Style() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
} |
|||
#pragma warning restore 1591
|
|||
@ -1,28 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!-- |
|||
This file specifies which parts of the BCL or Blazor packages must not be |
|||
stripped by the IL Linker even if they aren't referenced by user code. |
|||
--> |
|||
<linker> |
|||
<assembly fullname="mscorlib"> |
|||
<!-- |
|||
Preserve the methods in WasmRuntime because its methods are called by |
|||
JavaScript client-side code to implement timers. |
|||
Fixes: https://github.com/dotnet/blazor/issues/239 |
|||
--> |
|||
<type fullname="System.Threading.WasmRuntime"/> |
|||
</assembly> |
|||
|
|||
<assembly fullname="System.Core"> |
|||
<!-- |
|||
System.Linq.Expressions* is required by Json.NET and any |
|||
expression.Compile caller. The assembly isn't stripped. |
|||
--> |
|||
<type fullname="System.Linq.Expressions*"/> |
|||
</assembly> |
|||
<!-- |
|||
In this example, the app's entry point assembly is listed. The assembly |
|||
isn't stripped by the IL Linker. |
|||
--> |
|||
<assembly fullname="ControlCatalog" preserve="All" /> |
|||
</linker> |
|||
@ -1,186 +1,16 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform> |
|||
<ProjectGuid>{57E0455D-D565-44BB-B069-EE1AA20F8337}</ProjectGuid> |
|||
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
|||
<OutputType>Exe</OutputType> |
|||
<RootNamespace>ControlCatalog.iOS</RootNamespace> |
|||
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix> |
|||
<AssemblyName>ControlCatalogiOS</AssemblyName> |
|||
<MtouchEnableSGenConc>true</MtouchEnableSGenConc> |
|||
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler> |
|||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle> |
|||
<ProvisioningType>automatic</ProvisioningType> |
|||
<ProvisioningType>manual</ProvisioningType> |
|||
<TargetFramework>net6.0-ios</TargetFramework> |
|||
<SupportedOSPlatformVersion>10.0</SupportedOSPlatformVersion> |
|||
<!-- temporal workaround for our GL interface backend --> |
|||
<UseInterpreter>True</UseInterpreter> |
|||
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier> |
|||
<!-- <RuntimeIdentifier>ios-arm64</RuntimeIdentifier>--> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath> |
|||
<DefineConstants>DEBUG</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<ConsolePause>false</ConsolePause> |
|||
<MtouchArch>x86_64</MtouchArch> |
|||
<MtouchLink>None</MtouchLink> |
|||
<MtouchDebug>True</MtouchDebug> |
|||
<MtouchSdkVersion>9.1</MtouchSdkVersion> |
|||
<MtouchProfiling>False</MtouchProfiling> |
|||
<MtouchFastDev>False</MtouchFastDev> |
|||
<MtouchNoSymbolStrip>False</MtouchNoSymbolStrip> |
|||
<MtouchUseLlvm>False</MtouchUseLlvm> |
|||
<MtouchUseThumb>False</MtouchUseThumb> |
|||
<MtouchEnableBitcode>False</MtouchEnableBitcode> |
|||
<MtouchUseSGen>False</MtouchUseSGen> |
|||
<MtouchUseRefCounting>False</MtouchUseRefCounting> |
|||
<OptimizePNGs>True</OptimizePNGs> |
|||
<MtouchTlsProvider>Default</MtouchTlsProvider> |
|||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler> |
|||
<MtouchFloat32>False</MtouchFloat32> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' "> |
|||
<DebugType>none</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\iPhoneSimulator\Release</OutputPath> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<MtouchLink>None</MtouchLink> |
|||
<MtouchArch>x86_64</MtouchArch> |
|||
<ConsolePause>false</ConsolePause> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\iPhone\Debug</OutputPath> |
|||
<DefineConstants>DEBUG</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<ConsolePause>false</ConsolePause> |
|||
<MtouchArch>ARMv7, ARM64</MtouchArch> |
|||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> |
|||
<CodesignKey>iPhone Developer</CodesignKey> |
|||
<MtouchDebug>true</MtouchDebug> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> |
|||
<DebugType>none</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\iPhone\Release</OutputPath> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> |
|||
<MtouchArch>ARMv7, ARM64</MtouchArch> |
|||
<ConsolePause>false</ConsolePause> |
|||
<CodesignKey>iPhone Developer</CodesignKey> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' "> |
|||
<DebugType>none</DebugType> |
|||
<Optimize>True</Optimize> |
|||
<OutputPath>bin\iPhone\Ad-Hoc</OutputPath> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<ConsolePause>False</ConsolePause> |
|||
<MtouchArch>ARMv7, ARM64</MtouchArch> |
|||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> |
|||
<BuildIpa>True</BuildIpa> |
|||
<CodesignProvision>Automatic:AdHoc</CodesignProvision> |
|||
<CodesignKey>iPhone Distribution</CodesignKey> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' "> |
|||
<DebugType>none</DebugType> |
|||
<Optimize>True</Optimize> |
|||
<OutputPath>bin\iPhone\AppStore</OutputPath> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<ConsolePause>False</ConsolePause> |
|||
<MtouchArch>ARMv7, ARM64</MtouchArch> |
|||
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> |
|||
<CodesignProvision>Automatic:AppStore</CodesignProvision> |
|||
<CodesignKey>iPhone Distribution</CodesignKey> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Compile Include="Main.cs" /> |
|||
<Compile Include="AppDelegate.cs" /> |
|||
<None Include="Info.plist" /> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
<InterfaceDefinition Include="Resources\LaunchScreen.xib" /> |
|||
<Content Include="Entitlements.plist" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Xml" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="Xamarin.iOS" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj"> |
|||
<Project>{4488AD85-1495-4809-9AA4-DDFE0A48527E}</Project> |
|||
<Name>Avalonia.iOS</Name> |
|||
<IsAppExtension>false</IsAppExtension> |
|||
<IsWatchApp>false</IsWatchApp> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj"> |
|||
<Project>{3E53A01A-B331-47F3-B828-4A5717E77A24}</Project> |
|||
<Name>Avalonia.Markup.Xaml</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj"> |
|||
<Project>{6417E941-21BC-467B-A771-0DE389353CE6}</Project> |
|||
<Name>Avalonia.Markup</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Animation\Avalonia.Animation.csproj"> |
|||
<Project>{D211E587-D8BC-45B9-95A4-F297C8FA5200}</Project> |
|||
<Name>Avalonia.Animation</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Base\Avalonia.Base.csproj"> |
|||
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project> |
|||
<Name>Avalonia.Base</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Controls\Avalonia.Controls.csproj"> |
|||
<Project>{D2221C82-4A25-4583-9B43-D791E3F6820C}</Project> |
|||
<Name>Avalonia.Controls</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj"> |
|||
<Project>{7062AE20-5DCC-4442-9645-8195BDECE63E}</Project> |
|||
<Name>Avalonia.Diagnostics</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Input\Avalonia.Input.csproj"> |
|||
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project> |
|||
<Name>Avalonia.Input</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj"> |
|||
<Project>{6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}</Project> |
|||
<Name>Avalonia.Interactivity</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Layout\Avalonia.Layout.csproj"> |
|||
<Project>{42472427-4774-4C81-8AFF-9F27B8E31721}</Project> |
|||
<Name>Avalonia.Layout</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj"> |
|||
<Project>{EB582467-6ABB-43A1-B052-E981BA910E3A}</Project> |
|||
<Name>Avalonia.Visuals</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj"> |
|||
<Project>{F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}</Project> |
|||
<Name>Avalonia.Styling</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj"> |
|||
<Project>{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}</Project> |
|||
<Name>Avalonia.Themes.Default</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj"> |
|||
<Project>{7d2d3083-71dd-4cc9-8907-39a0d86fb322}</Project> |
|||
<Name>Avalonia.Skia</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj"> |
|||
<Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project> |
|||
<Name>ControlCatalog</Name> |
|||
</ProjectReference> |
|||
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.80.2-preview.33" /> |
|||
<ProjectReference Include="..\..\src\iOS\Avalonia.iOS\Avalonia.iOS.csproj" /> |
|||
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" /> |
|||
<Import Project="..\..\build\LegacyProject.targets" /> |
|||
<Import Project="..\..\build\SkiaSharp.props" /> |
|||
<Import Project="..\..\build\HarfBuzzSharp.props" /> |
|||
</Project> |
|||
</Project> |
|||
@ -1,36 +0,0 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle("ControlCatalog.iOS")] |
|||
[assembly: AssemblyDescription("")] |
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("ControlCatalog.iOS")] |
|||
[assembly: AssemblyCopyright("Copyright © 2016")] |
|||
[assembly: AssemblyTrademark("")] |
|||
[assembly: AssemblyCulture("")] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible(false)] |
|||
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|||
[assembly: Guid("57e0455d-d565-44bb-b069-ee1aa20f8337")] |
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion("1.0.0.0")] |
|||
[assembly: AssemblyFileVersion("1.0.0.0")] |
|||
@ -0,0 +1,18 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using Avalonia.Data.Converters; |
|||
|
|||
namespace ControlCatalog.Converter; |
|||
|
|||
public class MathSubtractConverter : IValueConverter |
|||
{ |
|||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) |
|||
{ |
|||
return (double)value - (double)parameter; |
|||
} |
|||
|
|||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="ControlCatalog.Pages.ButtonPage"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h2">A button control</TextBlock> |
|||
|
|||
<StackPanel Orientation="Horizontal" |
|||
Margin="0,16,0,0" |
|||
HorizontalAlignment="Center" |
|||
Spacing="16"> |
|||
<StackPanel Orientation="Vertical" Spacing="8" Width="200"> |
|||
<Button>Standard _XAML Button</Button> |
|||
<Button Foreground="White">Foreground</Button> |
|||
<Button Background="{DynamicResource SystemAccentColor}">Background</Button> |
|||
<Button IsEnabled="False">Disabled</Button> |
|||
<Button Content="Re-themed"> |
|||
<Button.Styles> |
|||
<Style> |
|||
<Style.Resources> |
|||
<SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ThemeControlHighBrush">DarkRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBorderBrush">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackground">DarkRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackgroundPressed">OrangeRed</SolidColorBrush> |
|||
</Style.Resources> |
|||
</Style> |
|||
</Button.Styles> |
|||
</Button> |
|||
<RepeatButton Name="RepeatButton"> |
|||
<TextBlock Name="RepeatButtonTextBlock" Text="Repeat Button: 0" /> |
|||
</RepeatButton> |
|||
<ToggleButton Content="Toggle Button"/> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Vertical" Spacing="8" Width="150"> |
|||
<Button BorderThickness="0">No Border</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}">Border Color</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" BorderThickness="4">Thick Border</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" BorderThickness="4" IsEnabled="False">Disabled</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" KeyboardNavigation.IsTabStop="False">IsTabStop=False</Button> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -1,29 +0,0 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ButtonPage : UserControl |
|||
{ |
|||
private int repeatButtonClickCount = 0; |
|||
|
|||
public ButtonPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
this.FindControl<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public void OnRepeatButtonClick(object sender, object args) |
|||
{ |
|||
repeatButtonClickCount++; |
|||
var textBlock = this.FindControl<TextBlock>("RepeatButtonTextBlock"); |
|||
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,254 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="ControlCatalog.Pages.ButtonsPage"> |
|||
|
|||
<UserControl.Resources> |
|||
|
|||
<MenuFlyout x:Key="SharedMenuFlyout" |
|||
Placement="Bottom"> |
|||
<MenuItem Header="Item 1"> |
|||
<MenuItem Header="Subitem 1" /> |
|||
<MenuItem Header="Subitem 2" /> |
|||
<MenuItem Header="Subitem 3" /> |
|||
</MenuItem> |
|||
<MenuItem Header="Item 2" |
|||
InputGesture="Ctrl+A" /> |
|||
<MenuItem Header="Item 3" /> |
|||
</MenuFlyout> |
|||
|
|||
</UserControl.Resources> |
|||
|
|||
<UserControl.Styles > |
|||
|
|||
<Style Selector="Border.header-border"> |
|||
<Setter Property="Background"> |
|||
<Setter.Value> |
|||
<SolidColorBrush Color="Gray" Opacity="0.5" /> |
|||
</Setter.Value> |
|||
</Setter> |
|||
<Setter Property="BorderBrush" Value="Gray" /> |
|||
<Setter Property="BorderThickness" Value="0.5" /> |
|||
<Setter Property="CornerRadius" Value="5,5,0,0" /> |
|||
<Setter Property="MaxWidth" Value="450" /> |
|||
<Setter Property="Padding" Value="10" /> |
|||
</Style> |
|||
|
|||
<Style Selector="TextBlock.header"> |
|||
<Setter Property="FontSize" Value="18" /> |
|||
<Setter Property="FontWeight" Value="Bold" /> |
|||
</Style> |
|||
|
|||
<Style Selector="Border.thin"> |
|||
<Setter Property="BorderBrush" Value="Gray" /> |
|||
<Setter Property="BorderThickness" Value="0.5" /> |
|||
<Setter Property="CornerRadius" Value="0,0,5,5" /> |
|||
<Setter Property="Margin" Value="0,0,0,15" /> |
|||
</Style> |
|||
|
|||
</UserControl.Styles> |
|||
|
|||
<!-- Styles and overall page design based on AcrylicPage --> |
|||
|
|||
<StackPanel Orientation="Vertical" |
|||
Width="450"> |
|||
|
|||
<!-- Button --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="Button" Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A standard button control</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Horizontal" |
|||
HorizontalAlignment="Center" |
|||
Spacing="10"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8" |
|||
Width="200"> |
|||
<Button>Standard _XAML Button</Button> |
|||
<Button Foreground="White">Foreground</Button> |
|||
<Button Background="{DynamicResource SystemAccentColor}">Background</Button> |
|||
<Button IsEnabled="False">Disabled</Button> |
|||
<Button Content="Re-themed"> |
|||
<Button.Styles> |
|||
<Style> |
|||
<Style.Resources> |
|||
<SolidColorBrush x:Key="ThemeBorderMidBrush">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ThemeControlHighBrush">DarkRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBorderBrush">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackground">DarkRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackgroundPointerOver">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonBackgroundPressed">OrangeRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonForeground">White</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonForegroundPointerOver">Black</SolidColorBrush> |
|||
<SolidColorBrush x:Key="ButtonForegroundPressed">Black</SolidColorBrush> |
|||
</Style.Resources> |
|||
</Style> |
|||
</Button.Styles> |
|||
</Button> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8" |
|||
Width="200"> |
|||
<Button BorderThickness="0">No Border</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}">Border Color</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" |
|||
BorderThickness="4">Thick Border</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" |
|||
BorderThickness="4" |
|||
IsEnabled="False">Disabled</Button> |
|||
<Button BorderBrush="{DynamicResource SystemAccentColor}" |
|||
KeyboardNavigation.IsTabStop="False">IsTabStop=False</Button> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<!-- ToggleButton --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="ToggleButton" |
|||
Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A button control with multiple states: checked, unchecked or indeterminate.</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8"> |
|||
<ToggleButton Content="Toggle Button" /> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<!-- RepeatButton --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="RepeatButton" |
|||
Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A button control that raises its Click event repeatedly when it is pressed and held.</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8"> |
|||
<RepeatButton Name="RepeatButton"> |
|||
<TextBlock Name="RepeatButtonTextBlock" |
|||
Text="Repeat Button: 0" /> |
|||
</RepeatButton> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<!-- DropDownButton --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="DropDownButton" |
|||
Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A button with an added drop-down chevron to visually indicate it has a flyout with additional actions.</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8"> |
|||
<DropDownButton Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Drop Down Button" /> |
|||
</DropDownButton> |
|||
<DropDownButton Padding="0,0,8,0"> |
|||
<Border Background="Teal" |
|||
HorizontalAlignment="Stretch" |
|||
VerticalAlignment="Stretch" |
|||
Height="32" |
|||
Width="32" /> |
|||
</DropDownButton> |
|||
<DropDownButton IsEnabled="False">Disabled</DropDownButton> |
|||
<DropDownButton /> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<!-- SplitButton --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="SplitButton" |
|||
Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A button with primary and secondary parts that can each be pressed separately. The primary part behaves like a Button and the secondary part opens a flyout.</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8"> |
|||
<SplitButton Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Content" /> |
|||
</SplitButton> |
|||
<SplitButton IsEnabled="False" |
|||
Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Disabled" /> |
|||
</SplitButton> |
|||
<SplitButton Flyout="{StaticResource SharedMenuFlyout}" |
|||
Content="Re-themed" |
|||
Foreground="White"> |
|||
<SplitButton.Styles> |
|||
<Style> |
|||
<Style.Resources> |
|||
<x:Double x:Key="SplitButtonSeparatorWidth">1.5</x:Double> |
|||
<Thickness x:Key="SplitButtonBorderThemeThickness">2</Thickness> |
|||
<SolidColorBrush x:Key="SplitButtonBorderBrush">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonBorderBrushPointerOver">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonBorderBrushPressed">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonBackground">DarkRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonBackgroundPointerOver">Red</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonBackgroundPressed">OrangeRed</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonForeground">White</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonForegroundPointerOver">Black</SolidColorBrush> |
|||
<SolidColorBrush x:Key="SplitButtonForegroundPressed">Black</SolidColorBrush> |
|||
</Style.Resources> |
|||
</Style> |
|||
</SplitButton.Styles> |
|||
</SplitButton> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<!-- ToggleSplitButton --> |
|||
<Border Classes="header-border"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="ToggleSplitButton" |
|||
Classes="header" /> |
|||
<TextBlock TextWrapping="Wrap">A button with primary and secondary parts that can each be pressed separately. The primary part behaves like a ToggleButton with two states and the secondary part opens a flyout.</TextBlock> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
<Border Classes="thin" |
|||
Padding="15"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="8"> |
|||
<ToggleSplitButton Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Content" /> |
|||
</ToggleSplitButton> |
|||
<ToggleSplitButton IsChecked="True" |
|||
Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Content" /> |
|||
</ToggleSplitButton> |
|||
<ToggleSplitButton IsChecked="True" |
|||
IsEnabled="False" |
|||
Flyout="{StaticResource SharedMenuFlyout}"> |
|||
<TextBlock Text="Disabled" /> |
|||
</ToggleSplitButton> |
|||
</StackPanel> |
|||
</Border> |
|||
|
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,29 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ButtonsPage : UserControl |
|||
{ |
|||
private int repeatButtonClickCount = 0; |
|||
|
|||
public ButtonsPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
this.FindControl<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public void OnRepeatButtonClick(object sender, object args) |
|||
{ |
|||
repeatButtonClickCount++; |
|||
var textBlock = this.FindControl<TextBlock>("RepeatButtonTextBlock"); |
|||
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
<UserControl x:Class="ControlCatalog.Pages.ClipboardPage" |
|||
xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h2">Example of ClipboardPage capabilities</TextBlock> |
|||
|
|||
<Button Click="CopyText" Content="Copy text to clipboard" /> |
|||
<Button Click="PasteText" Content="Paste text from clipboard" /> |
|||
<Button Click="CopyTextDataObject" Content="Copy text to clipboard (data object)" /> |
|||
<Button Click="PasteTextDataObject" Content="Paste text from clipboard (data object)" /> |
|||
|
|||
<Button Click="CopyFilesDataObject" Content="Copy files to clipboard (data object)" /> |
|||
<Button Click="PasteFilesDataObject" Content="Paste files from clipboard (data object)" /> |
|||
|
|||
<Button Click="GetFormats" Content="Get clipboard formats" /> |
|||
<Button Click="Clear" Content="Clear clipboard" /> |
|||
|
|||
<TextBox x:Name="ClipboardContent" |
|||
MinHeight="100" |
|||
AcceptsReturn="True" |
|||
Watermark="Text to copy of file names per line" /> |
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,77 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Input; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public partial class ClipboardPage : UserControl |
|||
{ |
|||
public ClipboardPage() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
private TextBox ClipboardContent => this.Get<TextBox>("ClipboardContent"); |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
private async void CopyText(object sender, RoutedEventArgs args) |
|||
{ |
|||
await Application.Current.Clipboard.SetTextAsync(ClipboardContent.Text); |
|||
} |
|||
|
|||
private async void PasteText(object sender, RoutedEventArgs args) |
|||
{ |
|||
ClipboardContent.Text = await Application.Current.Clipboard.GetTextAsync(); |
|||
} |
|||
|
|||
private async void CopyTextDataObject(object sender, RoutedEventArgs args) |
|||
{ |
|||
var dataObject = new DataObject(); |
|||
dataObject.Set(DataFormats.Text, ClipboardContent.Text ?? string.Empty); |
|||
await Application.Current.Clipboard.SetDataObjectAsync(dataObject); |
|||
} |
|||
|
|||
private async void PasteTextDataObject(object sender, RoutedEventArgs args) |
|||
{ |
|||
ClipboardContent.Text = await Application.Current.Clipboard.GetDataAsync(DataFormats.Text) as string ?? string.Empty; |
|||
} |
|||
|
|||
private async void CopyFilesDataObject(object sender, RoutedEventArgs args) |
|||
{ |
|||
var files = ClipboardContent.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); |
|||
if (files.Length == 0) |
|||
{ |
|||
return; |
|||
} |
|||
var dataObject = new DataObject(); |
|||
dataObject.Set(DataFormats.FileNames, files); |
|||
await Application.Current.Clipboard.SetDataObjectAsync(dataObject); |
|||
} |
|||
|
|||
private async void PasteFilesDataObject(object sender, RoutedEventArgs args) |
|||
{ |
|||
var fiels = await Application.Current.Clipboard.GetDataAsync(DataFormats.FileNames) as IEnumerable<string>; |
|||
ClipboardContent.Text = fiels != null ? string.Join(Environment.NewLine, fiels) : string.Empty; |
|||
} |
|||
|
|||
private async void GetFormats(object sender, RoutedEventArgs args) |
|||
{ |
|||
var formats = await Application.Current.Clipboard.GetFormatsAsync(); |
|||
ClipboardContent.Text = string.Join(Environment.NewLine, formats); |
|||
} |
|||
|
|||
private async void Clear(object sender, RoutedEventArgs args) |
|||
{ |
|||
await Application.Current.Clipboard.ClearAsync(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
xmlns:primitives="clr-namespace:Avalonia.Controls.Primitives;assembly=Avalonia.Controls" |
|||
xmlns:pc="clr-namespace:Avalonia.Controls.Primitives.Converters;assembly=Avalonia.Controls.ColorPicker" |
|||
mc:Ignorable="d" |
|||
d:DesignWidth="800" |
|||
d:DesignHeight="450" |
|||
x:Class="ControlCatalog.Pages.ColorPickerPage"> |
|||
|
|||
<UserControl.Resources> |
|||
<pc:ThirdComponentConverter x:Key="ThirdComponent" /> |
|||
</UserControl.Resources> |
|||
|
|||
<Grid ColumnDefinitions="Auto,10,Auto"> |
|||
<Grid Grid.Column="0" |
|||
Grid.Row="0" |
|||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto"> |
|||
<ColorSpectrum x:Name="ColorSpectrum1" |
|||
Grid.Row="0" |
|||
Color="Red" |
|||
CornerRadius="10" |
|||
Height="256" |
|||
Width="256" /> |
|||
<ColorSlider Grid.Row="1" |
|||
Margin="0,10,0,0" |
|||
ColorComponent="Component1" |
|||
ColorModel="Hsva" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> |
|||
<ColorSlider Grid.Row="2" |
|||
ColorComponent="Component2" |
|||
ColorModel="Hsva" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> |
|||
<ColorSlider Grid.Row="3" |
|||
ColorComponent="Component3" |
|||
ColorModel="Hsva" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> |
|||
<ColorSlider Grid.Row="4" |
|||
ColorComponent="Alpha" |
|||
ColorModel="Hsva" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> |
|||
<ColorPreviewer Grid.Row="5" |
|||
ShowAccentColors="True" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum1}" /> |
|||
</Grid> |
|||
<Grid Grid.Column="2" |
|||
Grid.Row="0" |
|||
ColumnDefinitions="Auto,Auto,Auto" |
|||
RowDefinitions="Auto,Auto"> |
|||
<ColorSlider Grid.Column="0" |
|||
Grid.Row="0" |
|||
IsAlphaMaxForced="True" |
|||
IsSaturationValueMaxForced="False" |
|||
ColorComponent="{Binding Components, ElementName=ColorSpectrum2, Converter={StaticResource ThirdComponent}}" |
|||
ColorModel="Hsva" |
|||
Orientation="Vertical" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum2}" /> |
|||
<ColorSpectrum x:Name="ColorSpectrum2" |
|||
Grid.Column="1" |
|||
Grid.Row="0" |
|||
Color="Green" |
|||
Shape="Ring" |
|||
Height="256" |
|||
Width="256" /> |
|||
<ColorSlider Grid.Column="2" |
|||
Grid.Row="0" |
|||
ColorComponent="Alpha" |
|||
ColorModel="Hsva" |
|||
Orientation="Vertical" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum2}" /> |
|||
<ColorPreviewer Grid.Column="0" |
|||
Grid.ColumnSpan="3" |
|||
Grid.Row="1" |
|||
ShowAccentColors="True" |
|||
HsvColor="{Binding HsvColor, ElementName=ColorSpectrum2}" /> |
|||
</Grid> |
|||
</Grid> |
|||
</UserControl> |
|||
@ -0,0 +1,19 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public partial class ColorPickerPage : UserControl |
|||
{ |
|||
public ColorPickerPage() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue