Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
44 changes: 44 additions & 0 deletions ReCap.CommonUI/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/

# Visual Studio Code
.vscode/

# Rider
.idea/

# Visual Studio
.vs/

# Fleet
.fleet/

# Code Rush
.cr/

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Pp]ublish/
msbuild.log
msbuild.err
msbuild.wrn
111 changes: 111 additions & 0 deletions ReCap.CommonUI/Attached/BindDynamicResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml.MarkupExtensions;

using AvPropChangedArgs = Avalonia.AvaloniaPropertyChangedEventArgs;

namespace ReCap.CommonUI
{
public class BindDynamicResource
: AvaloniaObject
{
public static readonly AttachedProperty<object> ResourceKeyProperty =
AvaloniaProperty.RegisterAttached<BindDynamicResource, Control, object>("ResourceKey", null);
public static object GetResourceKey(Control control)
=> control.GetValue(ResourceKeyProperty);
public static void SetResourceKey(Control control, double value)
=> control.SetValue(ResourceKeyProperty, value);


static BindDynamicResource()
{
ResourceKeyProperty.Changed.AddClassHandler<ContentControl>(ContentControl_ResourceKeyProperty_Changed);
ResourceKeyProperty.Changed.AddClassHandler<TemplatedControl>(TemplatedControl_ResourceKeyProperty_Changed);
ResourceKeyProperty.Changed.AddClassHandler<TextBlock>(TextBlock_ResourceKeyProperty_Changed);
}

static void ContentControl_ResourceKeyProperty_Changed(ContentControl control, AvPropChangedArgs args)
=> ResourceKeyProperty_Changed(control, args, ContentControl.ContentProperty);
static void TemplatedControl_ResourceKeyProperty_Changed(TemplatedControl control, AvPropChangedArgs args)
=> ResourceKeyProperty_Changed(control, args, TemplatedControl.TemplateProperty);
static void TextBlock_ResourceKeyProperty_Changed(TextBlock control, AvPropChangedArgs args)
=> ResourceKeyProperty_Changed(control, args, TextBlock.TextProperty);
/*
{
GetOldAndNewKey(args, out object oldKey, out object newKey);

if (oldKey == newKey)
return;
//control.Bind(TextBlock.TextProperty, new DynamicResourceExtension(newKey))
}
*/

static readonly Dictionary<WeakReference<Control>, IDisposable> _bindings = new();
static void ResourceKeyProperty_Changed<TControl>(TControl control, AvPropChangedArgs args, AvaloniaProperty prop)
where TControl : Control
{
GetOldAndNewKey(args, out object oldKey, out object newKey);

if (oldKey == newKey)
return;

//_bindings.Keys.FirstOrDefault(x => x.try)
if (TryGetBindingFor(control, out WeakReference<Control> key, out IDisposable prevBinding))
{
_bindings.Remove(key);
prevBinding.Dispose();
}

if (newKey == null)
return;

var newBinding = control.Bind(prop, new DynamicResourceExtension(newKey));
_bindings.Add(new(control), newBinding);
}

static bool TryGetBindingFor(Control control, out WeakReference<Control> key, out IDisposable binding)
{
var keys = (_bindings != null)
? _bindings.Keys
: null
;

if (keys == null)
goto fail;
if (keys.Count <= 0)
goto fail;


for (int i = 0; i < _bindings.Keys.Count; i++)
{
var k = _bindings.Keys.ElementAt(i);
if (k.TryGetTarget(out Control target))
{
if (target != control)
continue;

key = k;
binding = _bindings[k];
return true;
}
else
{
_bindings.Remove(k);
i--;
}
}

fail:
key = default;
binding = default;
return false;
}

static void GetOldAndNewKey(AvPropChangedArgs args, out object oldKey, out object newKey)
=> (oldKey, newKey) = args.GetOldAndNewValue<object>();
}
}
25 changes: 25 additions & 0 deletions ReCap.CommonUI/Attached/ScrollBarInset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using Avalonia;
using Avalonia.Controls;

namespace ReCap.CommonUI
{
public class ScrollBarInset
: AvaloniaObject
{
public static readonly AttachedProperty<double> VerticalProperty =
AvaloniaProperty.RegisterAttached<ScrollBarInset, ScrollViewer, double>("Vertical", 0.0);
public static double GetVertical(ScrollViewer control)
=> control.GetValue(VerticalProperty);
public static void SetVertical(ScrollViewer control, double value)
=> control.SetValue(VerticalProperty, value);


public static readonly AttachedProperty<double> HorizontalProperty =
AvaloniaProperty.RegisterAttached<ScrollBarInset, ScrollViewer, double>("Horizontal", 0.0);
public static double GetHorizontal(ScrollViewer control)
=> control.GetValue(HorizontalProperty);
public static void SetHorizontal(ScrollViewer control, double value)
=> control.SetValue(HorizontalProperty, value);
}
}
123 changes: 123 additions & 0 deletions ReCap.CommonUI/Attached/TextFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reactive;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Chrome;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Input;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Reactive;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace ReCap.CommonUI
{
public class TextFormatter
: AvaloniaObject
{
public static readonly AttachedProperty<TextFormatter> FormatterProperty =
AvaloniaProperty.RegisterAttached<TextFormatter, TextBlock, TextFormatter>("Formatter", null);
public static TextFormatter GetFormatter(TextBlock control)
=> control.GetValue(FormatterProperty);
public static void SetFormatter(TextBlock control, double value)
=> control.SetValue(FormatterProperty, value);



/// <summary>
/// Defines the <see cref="FormatKey"/> property.
/// </summary>
public static readonly StyledProperty<object> FormatKeyProperty =
AvaloniaProperty.Register<TextFormatter, object>(nameof(FormatKey), null);

public object FormatKey
{
get => GetValue(FormatKeyProperty);
set => SetValue(FormatKeyProperty, value);
}


/// <summary>
/// Defines the <see cref="Format"/> property.
/// </summary>
public static readonly StyledProperty<string> FormatProperty =
AvaloniaProperty.Register<TextFormatter, string>(nameof(Format), null);

public string Format
{
get => GetValue(FormatProperty);
set => SetValue(FormatProperty, value);
}


static TextFormatter()
{
FormatterProperty.Changed.AddClassHandler<TextBlock>(FormatterProperty_Changed);
FormatKeyProperty.Changed.AddClassHandler<TextFormatter>(ResourceKeyProperty_Changed);
}

static void FormatterProperty_Changed(TextBlock arg1, AvaloniaPropertyChangedEventArgs arg2)
{
throw new NotImplementedException();
}

static void ResourceKeyProperty_Changed(TextFormatter s, AvaloniaPropertyChangedEventArgs args)
=> s?.OnResourceKeyPropertyChanged(args);

IDisposable _prevBinding = null;
void OnResourceKeyPropertyChanged(AvaloniaPropertyChangedEventArgs args)
{
_prevBinding?.Dispose();


var newKey = args.NewValue;
if (newKey == null)
return;

var newBinding = this.Bind(FormatProperty, new DynamicResourceExtension(newKey));
_prevBinding = newBinding;
}


static bool TryGetAsBoolean(object obj, out bool value)
{
if (obj == null)
{
value = default;
return false;
}

if (obj is bool val)
{
value = val;
return true;
}

string objStr = (obj is string str)
? str
: obj.ToString()
;

return bool.TryParse(objStr, out value);
}


public object Convert(IList<object> values, Type targetType, object parameter, CultureInfo culture)
{
if (!(values[0] is TextBlock avObj))
return BindingOperations.DoNothing;

object[] args = values
.Skip(1)
.ToArray()
;

return string.Format(Format, args);
}
}
}
60 changes: 60 additions & 0 deletions ReCap.CommonUI/Attached/WindowChromeAddon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia;
using Avalonia.Controls;

namespace ReCap.CommonUI
{
public partial class WindowChromeAddon
: AvaloniaObject
{
public static readonly AttachedProperty<bool> ManagedShowTitleProperty =
AvaloniaProperty.RegisterAttached<WindowChromeAddon, Window, bool>("ManagedShowTitle", true);
public static bool GetManagedShowTitle(Window control)
=> control.GetValue(ManagedShowTitleProperty);
public static void SetManagedShowTitle(Window control, bool value)
=> control.SetValue(ManagedShowTitleProperty, value);




static bool DefaultToLeftSideButtons => OSInfo.IsMacOS;
public static readonly AttachedProperty<bool> LeftSideButtonsProperty =
AvaloniaProperty.RegisterAttached<WindowChromeAddon, Window, bool>("LeftSideButtons", DefaultToLeftSideButtons);
public static bool GetLeftSideButtons(Window control)
=> control.GetValue(LeftSideButtonsProperty);
public static void SetLeftSideButtons(Window control, bool value)
=> control.SetValue(LeftSideButtonsProperty, value);




public static readonly AttachedProperty<bool> UseTransparencyHackHintProperty =
AvaloniaProperty.RegisterAttached<WindowChromeAddon, Window, bool>("UseTransparencyHackHint", false);
public static bool GetUseTransparencyHackHint(Window control)
=> control.GetValue(UseTransparencyHackHintProperty);
public static void SetUseTransparencyHackHint(Window control, bool value)
=> control.SetValue(UseTransparencyHackHintProperty, value);




public static readonly AttachedProperty<bool> ActualUseTransparencyHackProperty =
AvaloniaProperty.RegisterAttached<WindowChromeAddon, Window, bool>("ActualUseTransparencyHack", false);
public static bool GetActualUseTransparencyHack(Window control)
=> control.GetValue(ActualUseTransparencyHackProperty);
static void SetActualUseTransparencyHack(Window control, bool value)
=> control.SetValue(ActualUseTransparencyHackProperty, value);




static WindowChromeAddon()
{
UseTransparencyHackHintProperty.Changed.AddClassHandler<Window>(UseTransparencyHackHintProperty_Changed);
ActualUseTransparencyHackProperty.Changed.AddClassHandler<Window>(ActualUseTransparencyHackProperty_Changed);
}
}
}
Loading