Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Themes #2735

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions src/Eto.Mac/Forms/ApplicationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Runtime.CompilerServices;
namespace Eto.Mac.Forms
{
public class ApplicationHandler : WidgetHandler<NSApplication, Application, Application.ICallback>, Application.IHandler
public class ApplicationHandler : MacObject<NSApplication, Application, Application.ICallback>, Application.IHandler
{
bool attached;

Expand Down Expand Up @@ -115,7 +115,7 @@ static void restart_WillTerminate(object sender, EventArgs e)
var args = new string[]
{
"-c",
"open \"$1\"",
"open \"$1\"",
string.Empty,
NSBundle.MainBundle.BundlePath
};
Expand All @@ -129,7 +129,7 @@ public void Invoke(Action action)
else
Control.InvokeOnMainThread(action);
}

public void AsyncInvoke(Action action)
{
Control.BeginInvokeOnMainThread(action);
Expand All @@ -150,23 +150,23 @@ public void Restart()
Control.Delegate = oldDelegate;
}

static readonly IntPtr selNextEventMatchingMaskUntilDateInModeDequeue_Handle = Selector.GetHandle ("nextEventMatchingMask:untilDate:inMode:dequeue:");
static readonly IntPtr selSendEvent_Handle = Selector.GetHandle ("sendEvent:");
static readonly IntPtr selNextEventMatchingMaskUntilDateInModeDequeue_Handle = Selector.GetHandle("nextEventMatchingMask:untilDate:inMode:dequeue:");
static readonly IntPtr selSendEvent_Handle = Selector.GetHandle("sendEvent:");

public void RunIteration()
{
MacView.InMouseTrackingLoop = false;
// drain the event queue only for a short period of time so it doesn't lock up
var date = NSDate.FromTimeIntervalSinceNow(0.001);
for (;;)
for (; ; )
{
// dequeue the event
var evt = Control.NextEvent(NSEventMask.AnyEvent, date, NSRunLoopMode.Default, true);

// no event? cool, let's get out of here
if (evt == null)
break;

// dispatch the event
Control.SendEvent(evt);
}
Expand Down Expand Up @@ -196,7 +196,7 @@ public void Run()


EtoBundle.Init();

EtoFontManager.Install();

if (Control.Delegate == null)
Expand Down Expand Up @@ -227,7 +227,7 @@ public void Open(string url)

#if Mac64
delegate void UncaughtExceptionHandlerDelegate(IntPtr nsexceptionPtr);

[DllImport(Constants.FoundationLibrary)]
static extern void NSSetUncaughtExceptionHandler(UncaughtExceptionHandlerDelegate handler);

Expand Down Expand Up @@ -275,6 +275,12 @@ public override void AttachEvent(string id)
NSNotificationCenter.DefaultCenter.AddObserver(NSApplication.DidBecomeActiveNotification, SharedApplication_ActiveChanged);
NSNotificationCenter.DefaultCenter.AddObserver(NSApplication.DidResignActiveNotification, SharedApplication_ActiveChanged);
break;
case Application.CurrentThemeChangedEvent:
AddControlObserver(new NSString("effectiveAppearance"), e =>
{
Callback.OnThemeChanged(Widget, EventArgs.Empty);
});
break;
default:
base.AttachEvent(id);
break;
Expand Down Expand Up @@ -325,5 +331,18 @@ public void EnableFullScreen()
public Keys AlternateModifier => Keys.Alt;

public bool IsActive => NSApplication.SharedApplication.Active;

public Theme CurrentTheme
{
get
{
var appearance = NSApplication.SharedApplication.Appearance;
return new Theme(new ThemeHandler(appearance));
}
set
{
NSApplication.SharedApplication.Appearance = ThemeHandler.GetControl(value);
}
}
}
}
60 changes: 60 additions & 0 deletions src/Eto.Mac/Forms/ThemeHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Eto.Mac.Forms;

public class ThemeHandler : WidgetHandler<NSAppearance, Theme>, Theme.IHandler
{
public ThemeHandler(NSAppearance appearance)
{
Control = appearance;
}

public string Name
{
get
{
var name = Control?.Name.ToString() ?? Application.Instance.Localize(Widget, "System");
if (name.StartsWith("NSAppearanceName"))
return name.Substring("NSAppearanceName".Length);
return name;
}
}

public ThemeStyle Style => Control.Name.ToString().ToLowerInvariant().Contains("dark") ? ThemeStyle.Dark : ThemeStyle.Light;

public override bool Equals(object obj)
{
if (obj is ThemeHandler themeHandler)
{
if (Control == null && themeHandler.Control == null)
return true;
return Control.Equals(themeHandler.Control);
}
return base.Equals(obj);
}

public override int GetHashCode()
{
return Control?.GetHashCode() ?? 0;
}
}

public class ThemesHandler : Themes.IHandler
{
public Theme System => new Theme(new ThemeHandler(null));
public Theme Light => new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameAqua)));
public Theme Dark => new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameDarkAqua)));
public Theme None => System;

public IEnumerable<Theme> GetThemes()
{
yield return new Theme(new ThemeHandler(null));
yield return new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameAqua)));
yield return new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameDarkAqua)));
yield return new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameVibrantLight)));
yield return new Theme(new ThemeHandler(NSAppearance.GetAppearance(NSAppearance.NameVibrantDark)));
}
}
1 change: 1 addition & 0 deletions src/Eto.Mac/Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ public static void AddTo(Eto.Platform p)
p.Add<DataFormats.IHandler>(() => new DataFormatsHandler());
p.Add<Taskbar.IHandler>(() => new TaskbarHandler());
p.Add<Window.IWindowHandler>(() => new WindowHandler());
p.Add<Themes.IHandler>(() => new ThemesHandler());

// IO
p.Add<SystemIcons.IHandler>(() => new SystemIconsHandler());
Expand Down
2 changes: 1 addition & 1 deletion src/Eto.Wpf/Eto.Wpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<!-- Suppress warning NU1701: Package 'Extended.Wpf.Toolkit 3.2.0' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v3.0'. This package may not be fully compatible with your project. -->
<NoWarn>NU1701;MSB4011;$(NoWarn)</NoWarn>
<NoWarn>NU1701;MSB4011;WPF0001;$(NoWarn)</NoWarn>
</PropertyGroup>

<PropertyGroup>
Expand Down
22 changes: 22 additions & 0 deletions src/Eto.Wpf/Forms/ApplicationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,35 @@ public Keys AlternateModifier
get { return Keys.Alt; }
}

public Theme CurrentTheme
{
get
{
#if NET9_0_OR_GREATER
return new Theme(new ThemeHandler(Control.ThemeMode));
#else
return null;
#endif
}
set
{
#if NET9_0_OR_GREATER
Control.ThemeMode = ThemeHandler.GetControl(value);
#endif
}
}


public void Open(string url)
{
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}

public void Run()
{
#if NET9_0_OR_GREATER
// Control.ThemeMode = sw.ThemeMode.System;
#endif
Callback.OnInitialized(Widget, EventArgs.Empty);
if (!_attached)
{
Expand Down
50 changes: 50 additions & 0 deletions src/Eto.Wpf/Forms/ThemeHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Eto.Wpf.Forms;

#if NET9_0_OR_GREATER

public class ThemeHandler : WidgetHandler<sw.ThemeMode, Theme, Theme.ICallback>, Theme.IHandler
{
public ThemeHandler(sw.ThemeMode mode)
{
Control = mode;
}

public string Name => Control.ToString();

public ThemeStyle Style
{
get
{
if (Control == sw.ThemeMode.System)
return ThemeStyle.System;
if (Control == sw.ThemeMode.Light)
return ThemeStyle.Light;
if (Control == sw.ThemeMode.Dark)
return ThemeStyle.Dark;
return ThemeStyle.Light;
}
}
}

public class ThemesHandler : Themes.IHandler
{
public Theme Light => new Theme(new ThemeHandler(sw.ThemeMode.Light));
public Theme Dark => new Theme(new ThemeHandler(sw.ThemeMode.Dark));
public Theme System => new Theme(new ThemeHandler(sw.ThemeMode.System));
public Theme None => new Theme(new ThemeHandler(sw.ThemeMode.None));

public IEnumerable<Theme> GetThemes()
{
yield return new Theme(new ThemeHandler(sw.ThemeMode.System));
yield return new Theme(new ThemeHandler(sw.ThemeMode.Light));
yield return new Theme(new ThemeHandler(sw.ThemeMode.Dark));
yield return new Theme(new ThemeHandler(sw.ThemeMode.None));
}
}

#endif
3 changes: 3 additions & 0 deletions src/Eto.Wpf/Platform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ public static void AddTo(Eto.Platform p)
p.Add<DataFormats.IHandler>(() => new DataFormatsHandler());
p.Add<Taskbar.IHandler>(() => new TaskbarHandler());
p.Add<Window.IWindowHandler>(() => new WindowHandler());
#if NET9_0_OR_GREATER
p.Add<Themes.IHandler>(() => new ThemesHandler());
#endif

// IO
p.Add<SystemIcons.IHandler>(() => new SystemIconsHandler());
Expand Down
2 changes: 1 addition & 1 deletion src/Eto.Wpf/themes/controls/DataGrid.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</Style>

<Style TargetType="efc:EtoDataGrid">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<!-- <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>-->
</Style>

</ResourceDictionary>
2 changes: 1 addition & 1 deletion src/Eto.Wpf/themes/controls/Window.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
xmlns:local="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit">

<Style TargetType="ef:EtoWindowContent">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<!--<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>-->
</Style>

</ResourceDictionary>
25 changes: 25 additions & 0 deletions src/Eto/Forms/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,13 +272,30 @@ void HandleClosed(object sender, EventArgs e)
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }

public Theme CurrentTheme
{
get => Handler.CurrentTheme;
set => Handler.CurrentTheme = value;
}

public const string CurrentThemeChangedEvent = "Application.CurrentThemeChanged";

public event EventHandler<EventArgs> CurrentThemeChanged
{
add { Properties.AddHandlerEvent(CurrentThemeChangedEvent, value); }
remove { Properties.RemoveEvent(CurrentThemeChangedEvent, value); }
}

protected virtual void OnCurrentThemeChanged(EventArgs e) => Properties.TriggerEvent(CurrentThemeChangedEvent, this, e);

static Application()
{
EventLookup.Register<Application>(c => c.OnTerminating(null), Application.TerminatingEvent);
EventLookup.Register<Application>(c => c.OnUnhandledException(null), Application.UnhandledExceptionEvent);
EventLookup.Register<Application>(c => c.OnNotificationActivated(null), Application.NotificationActivatedEvent);
EventLookup.Register<Application>(c => c.OnIsActiveChanged(null), Application.IsActiveChangedEvent);
EventLookup.Register<Application>(c => c.OnCurrentThemeChanged(null), Application.CurrentThemeChangedEvent);
}

/// <summary>
Expand Down Expand Up @@ -609,6 +626,7 @@ public string Localize(object source, string text)
/// Raises the IsActiveChanged event.
/// </summary>
void OnIsActiveChanged(Application wiget, EventArgs e);
void OnThemeChanged(Application wiget, EventArgs e);
}

/// <summary>
Expand Down Expand Up @@ -659,6 +677,12 @@ public void OnIsActiveChanged(Application widget, EventArgs e)
using (widget.Platform.Context)
widget.OnIsActiveChanged(e);
}

public void OnThemeChanged(Application widget, EventArgs e)
{
using (widget.Platform.Context)
widget.OnCurrentThemeChanged(e);
}
}

/// <summary>
Expand Down Expand Up @@ -767,5 +791,6 @@ public void OnIsActiveChanged(Application widget, EventArgs e)
/// Gets a value indicating that the application is currently the active application
/// </summary>
bool IsActive { get; }
Theme CurrentTheme { get; set; }
}
}
Loading
Loading