Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/xwt.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVsevolod Kukol <sevoku@microsoft.com>2017-03-06 21:17:16 +0300
committerVsevolod Kukol <sevoku@microsoft.com>2017-03-06 21:17:16 +0300
commitde0715a3fc95dfa778e09659eb3fa413a68eb656 (patch)
treeec966a4e4fc5696742946f3e785a24d66f1d5f15
parent1e937afc891f680880e0ae5118ee9a70fa739bab (diff)
parentad878125a61299c290f1689e3c247a48821fbf2d (diff)
Merge remote-tracking branch 'origin/add-popup-window' into monodevelop-native-popupsmonodevelop-native-popups
-rw-r--r--TestApps/Samples/MainWindow.cs1
-rw-r--r--TestApps/Samples/Samples.csproj1
-rw-r--r--TestApps/Samples/Samples/PopupWindows.cs86
-rw-r--r--TestApps/XamMacTest/XamMacTest.csproj2
-rw-r--r--Xwt.Gtk/Xwt.Gtk.csproj2
-rw-r--r--Xwt.Gtk/Xwt.Gtk3.csproj2
-rw-r--r--Xwt.Gtk/Xwt.GtkBackend/Gtk2PopoverWindow.cs66
-rw-r--r--Xwt.Gtk/Xwt.GtkBackend/Gtk3PopoverWindow.cs88
-rwxr-xr-xXwt.Gtk/Xwt.GtkBackend/GtkEngine.cs2
-rw-r--r--Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs38
-rw-r--r--Xwt.Gtk/Xwt.GtkBackend/PopupWindowBackend.cs63
-rw-r--r--Xwt.Gtk/Xwt.GtkBackend/UtilityWindowBackend.cs43
-rwxr-xr-xXwt.Gtk/Xwt.GtkBackend/WindowBackend.cs16
-rw-r--r--Xwt.WPF/Xwt.WPFBackend/WPFEngine.cs2
-rw-r--r--Xwt.WPF/Xwt.WPFBackend/WindowBackend.cs33
-rw-r--r--Xwt.WPF/Xwt.WPFBackend/WindowFrameBackend.cs8
-rw-r--r--Xwt.XamMac/Xwt.Mac/MacEngine.cs2
-rw-r--r--Xwt.XamMac/Xwt.Mac/PopupWindowBackend.cs617
-rw-r--r--Xwt.XamMac/Xwt.Mac/WindowBackend.cs10
-rw-r--r--Xwt.XamMac/Xwt.XamMac.csproj1
-rw-r--r--Xwt/Xwt.Backends/IPopupWindowBackend.cs33
-rw-r--r--Xwt/Xwt.Backends/IUtilityWindowBackend.cs32
-rwxr-xr-xXwt/Xwt.Backends/IWindowBackend.cs2
-rw-r--r--Xwt/Xwt.csproj3
-rw-r--r--Xwt/Xwt/PopupWindow.cs52
-rw-r--r--Xwt/Xwt/UtilityWindow.cs57
-rw-r--r--Xwt/Xwt/WidgetSpacing.cs45
-rw-r--r--Xwt/Xwt/Window.cs16
28 files changed, 1266 insertions, 57 deletions
diff --git a/TestApps/Samples/MainWindow.cs b/TestApps/Samples/MainWindow.cs
index caab05a0..7523dc47 100644
--- a/TestApps/Samples/MainWindow.cs
+++ b/TestApps/Samples/MainWindow.cs
@@ -135,6 +135,7 @@ namespace Samples
var windows = AddSample (null, "Windows", typeof(Windows));
AddSample (windows, "Message Dialogs", typeof(MessageDialogs));
+ AddSample (windows, "Popup Windows", typeof(PopupWindows));
AddSample (null, "Screens", typeof (ScreensSample));
diff --git a/TestApps/Samples/Samples.csproj b/TestApps/Samples/Samples.csproj
index 7c3933ef..3bbe0b5a 100644
--- a/TestApps/Samples/Samples.csproj
+++ b/TestApps/Samples/Samples.csproj
@@ -117,6 +117,7 @@
<Compile Include="Samples\FileSelectorSample.cs" />
<Compile Include="Samples\FolderSelectorSample.cs" />
<Compile Include="Samples\ListViewCombos.cs" />
+ <Compile Include="Samples\PopupWindows.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/TestApps/Samples/Samples/PopupWindows.cs b/TestApps/Samples/Samples/PopupWindows.cs
new file mode 100644
index 00000000..e21d2925
--- /dev/null
+++ b/TestApps/Samples/Samples/PopupWindows.cs
@@ -0,0 +1,86 @@
+//
+// PopupWindows.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 (c) Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using Xwt;
+using Xwt.Drawing;
+
+namespace Samples
+{
+ public class PopupWindows : VBox
+ {
+ public PopupWindows ()
+ {
+ var btn1 = new Button ("Show Utility Window");
+ UtilityWindow utility = null;
+ btn1.Clicked += (sender, e) => {
+ if (utility == null) {
+ utility = new UtilityWindow ();
+ utility.TransientFor = ParentWindow;
+ utility.InitialLocation = WindowLocation.CenterParent;
+ utility.Title = "Utility";
+ var content = new VBox ();
+ content.PackStart (new Label ("Utility Window"));
+ var btn = new Button ("Close");
+ btn.Clicked += delegate { utility.Close (); };
+ content.PackStart (btn);
+ utility.Content = content;
+ }
+ utility.Show ();
+ };
+
+ PackStart (btn1);
+
+
+ var btn2 = new Button ("Show custom Tooltip Window");
+ PopupWindow popup2 = null;
+ btn2.Clicked += (sender, e) => {
+ if (popup2 == null) {
+ popup2 = new PopupWindow (PopupWindow.PopupType.Tooltip);
+ popup2.TransientFor = ParentWindow;
+ popup2.Decorated = false;
+ popup2.Title = "Tooltip";
+ popup2.BackgroundColor = Colors.Blue.WithAlpha (0.7);
+ var l = new Label ("Tooltip Window");
+ l.Margin = 5;
+ l.TextColor = Colors.White;
+ l.MouseExited += (sl, el) => popup2.Hide ();
+ l.VerticalPlacement = l.HorizontalPlacement = WidgetPlacement.Center;
+ l.Margin = new WidgetSpacing (5, 4, 5, 4);
+
+ popup2.Content = l;
+ }
+ if (!popup2.Visible) {
+ btn2.Label = "Hide custom Tooltip Window";
+ popup2.Show ();
+ } else {
+ btn2.Label = "Show custom Tooltip Window";
+ popup2.Hide ();
+ }
+ };
+
+ PackStart (btn2);
+ }
+ }
+}
diff --git a/TestApps/XamMacTest/XamMacTest.csproj b/TestApps/XamMacTest/XamMacTest.csproj
index e60d3b2e..37f2bdb4 100644
--- a/TestApps/XamMacTest/XamMacTest.csproj
+++ b/TestApps/XamMacTest/XamMacTest.csproj
@@ -47,7 +47,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.Mac">
- <HintPath>\Library\Frameworks\Xamarin.Mac.framework\Versions\Current\lib\x86_64\full\Xamarin.Mac.dll</HintPath>
+ <HintPath>\Library\Frameworks\Xamarin.Mac.framework\Versions\Current\lib\i386\full\Xamarin.Mac.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
diff --git a/Xwt.Gtk/Xwt.Gtk.csproj b/Xwt.Gtk/Xwt.Gtk.csproj
index 05018ec1..efe612cf 100644
--- a/Xwt.Gtk/Xwt.Gtk.csproj
+++ b/Xwt.Gtk/Xwt.Gtk.csproj
@@ -157,6 +157,8 @@
<Compile Include="Xwt.GtkBackend\FontSelectorBackend.cs" />
<Compile Include="Xwt.GtkBackend\SelectFontDialogBackend.cs" />
<Compile Include="Xwt.GtkBackend.CellViews\CustomCellRendererComboBox.cs" />
+ <Compile Include="Xwt.GtkBackend\PopupWindowBackend.cs" />
+ <Compile Include="Xwt.GtkBackend\UtilityWindowBackend.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/Xwt.Gtk/Xwt.Gtk3.csproj b/Xwt.Gtk/Xwt.Gtk3.csproj
index ac879947..04c262ef 100644
--- a/Xwt.Gtk/Xwt.Gtk3.csproj
+++ b/Xwt.Gtk/Xwt.Gtk3.csproj
@@ -160,6 +160,8 @@
<Compile Include="Xwt.GtkBackend\SelectFontDialogBackend.cs" />
<Compile Include="Xwt.GtkBackend\Gtk3FontChooserDialog.cs" />
<Compile Include="Xwt.GtkBackend\FontSelectorBackend.cs" />
+ <Compile Include="Xwt.GtkBackend\PopupWindowBackend.cs" />
+ <Compile Include="Xwt.GtkBackend\UtilityWindowBackend.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/Xwt.Gtk/Xwt.GtkBackend/Gtk2PopoverWindow.cs b/Xwt.Gtk/Xwt.GtkBackend/Gtk2PopoverWindow.cs
index 63ff5549..6f575e5c 100644
--- a/Xwt.Gtk/Xwt.GtkBackend/Gtk2PopoverWindow.cs
+++ b/Xwt.Gtk/Xwt.GtkBackend/Gtk2PopoverWindow.cs
@@ -28,40 +28,74 @@ using Cairo;
namespace Xwt.GtkBackend
{
- public abstract class GtkPopoverWindow : Gtk.Window
+ public class GtkPopoverWindow : Gtk.Window
{
- protected bool supportAlpha;
+ bool supportAlpha;
+ protected bool SupportAlpha {
+ get {
+ return supportAlpha;
+ }
+ private set {
+ if (supportAlpha != value) {
+ supportAlpha = value;
+ OnSupportAlphaChanged ();
+ }
+ }
+ }
+
+ protected virtual void OnSupportAlphaChanged ()
+ {
+ QueueDraw ();
+ }
- protected GtkPopoverWindow (Gtk.WindowType type) : base (type)
- {}
+ public Color? BackgroundColor { get; set; }
- protected override void OnScreenChanged (Gdk.Screen previous_screen)
+ public GtkPopoverWindow (Gtk.WindowType type) : base (type)
+ {
+ AppPaintable = true;
+ UpdateColorMap ();
+ }
+
+ void UpdateColorMap ()
{
// To check if the display supports alpha channels, get the colormap
- var colormap = this.Screen.RgbaColormap;
+ var colormap = Screen.RgbaColormap;
if (colormap == null) {
- colormap = this.Screen.RgbColormap;
- supportAlpha = false;
- } else {
- supportAlpha = true;
- }
- this.Colormap = colormap;
+ colormap = Screen.RgbColormap;
+ SupportAlpha = false;
+ } else
+ SupportAlpha = true;
+ Colormap = colormap;
+ }
+
+ protected override void OnScreenChanged (Gdk.Screen previous_screen)
+ {
+ UpdateColorMap ();
base.OnScreenChanged (previous_screen);
}
- protected virtual bool OnDrawn (Cairo.Context cr)
+ protected virtual bool OnDraw (Cairo.Context cr)
{
return false;
}
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
{
+ bool handled;
using (Context ctx = Gdk.CairoHelper.Create (this.GdkWindow)) {
- OnDrawn (ctx);
+ if (BackgroundColor.HasValue) {
+ // We clear the surface with a transparent color if possible
+ if (SupportAlpha && BackgroundColor.Value.A < 1.0)
+ ctx.SetSourceRGBA (BackgroundColor.Value.R, BackgroundColor.Value.G, BackgroundColor.Value.B, BackgroundColor.Value.A);
+ else
+ ctx.SetSourceRGB (BackgroundColor.Value.R, BackgroundColor.Value.G, BackgroundColor.Value.B);
+ ctx.Operator = Operator.Source;
+ ctx.Paint ();
+ }
+ handled = OnDraw (ctx);
}
- base.OnExposeEvent (evnt);
- return false;
+ return handled || base.OnExposeEvent (evnt);
}
}
}
diff --git a/Xwt.Gtk/Xwt.GtkBackend/Gtk3PopoverWindow.cs b/Xwt.Gtk/Xwt.GtkBackend/Gtk3PopoverWindow.cs
index f91d2858..5f22e58c 100644
--- a/Xwt.Gtk/Xwt.GtkBackend/Gtk3PopoverWindow.cs
+++ b/Xwt.Gtk/Xwt.GtkBackend/Gtk3PopoverWindow.cs
@@ -28,31 +28,89 @@ using Cairo;
namespace Xwt.GtkBackend
{
- public abstract class GtkPopoverWindow : Gtk.Window
+ public class GtkPopoverWindow : Gtk.Window
{
protected bool supportAlpha = true;
+ protected bool SupportAlpha
+ {
+ get
+ {
+ return supportAlpha;
+ }
+ private set
+ {
+ if (supportAlpha != value)
+ {
+ supportAlpha = value;
+ OnSupportAlphaChanged();
+ }
+ }
+ }
+
+ protected virtual void OnSupportAlphaChanged()
+ {
+ QueueDraw();
+ }
+
+ Color? backgroundColor;
+
+ public Color? BackgroundColor
+ {
+ get { return backgroundColor; }
+ set {
+ backgroundColor = value;
+ // HACK: with AppPaintable == false Gtk3 doesn't draw the default background.
+ // Set AppPaintable = true only if a color is not null and is transparent.
+ AppPaintable = backgroundColor?.A < 1.0;
+ }
+ }
- protected GtkPopoverWindow (Gtk.WindowType type) : base (type)
- {}
+ public GtkPopoverWindow (Gtk.WindowType type) : base (type)
+ {
+ UpdateColorMap();
+ }
- protected override void OnScreenChanged (Gdk.Screen previous_screen)
+ void UpdateColorMap()
{
// To check if the display supports alpha channels, get the colormap
- var visual = this.Screen.RgbaVisual;
- if (visual == null) {
- visual = this.Screen.SystemVisual;
- supportAlpha = false;
- } else {
- supportAlpha = true;
+ var visual = Screen.RgbaVisual;
+ if (visual == null)
+ {
+ visual = Screen.SystemVisual;
+ SupportAlpha = false;
}
- this.Visual = visual;
- base.OnScreenChanged (previous_screen);
+ else
+ SupportAlpha = true;
+ Visual = visual;
+ }
+
+ protected override void OnScreenChanged(Gdk.Screen previous_screen)
+ {
+ UpdateColorMap();
+ base.OnScreenChanged(previous_screen);
}
- protected override bool OnDrawn (Context cr)
+ protected virtual bool OnDraw (Cairo.Context cr)
{
- cr.Restore ();
- return base.OnDrawn (cr);
+ return false;
+ }
+
+ protected sealed override bool OnDrawn (Context cr)
+ {
+ if (BackgroundColor.HasValue)
+ {
+ // We clear the surface with a transparent color if possible
+ if (SupportAlpha && BackgroundColor.Value.A < 1.0)
+ cr.SetSourceRGBA(BackgroundColor.Value.R, BackgroundColor.Value.G, BackgroundColor.Value.B, BackgroundColor.Value.A);
+ else
+ cr.SetSourceRGB(BackgroundColor.Value.R, BackgroundColor.Value.G, BackgroundColor.Value.B);
+ cr.Operator = Operator.Source;
+ cr.Paint();
+ }
+ var handled = OnDraw (cr);
+ cr.Restore();
+
+ return handled || base.OnDrawn (cr);
}
}
}
diff --git a/Xwt.Gtk/Xwt.GtkBackend/GtkEngine.cs b/Xwt.Gtk/Xwt.GtkBackend/GtkEngine.cs
index 9b8e8ed0..085f8538 100755
--- a/Xwt.Gtk/Xwt.GtkBackend/GtkEngine.cs
+++ b/Xwt.Gtk/Xwt.GtkBackend/GtkEngine.cs
@@ -114,6 +114,8 @@ namespace Xwt.GtkBackend
RegisterBackend<ICalendarBackend, CalendarBackend> ();
RegisterBackend<IFontSelectorBackend, FontSelectorBackend> ();
RegisterBackend<ISelectFontDialogBackend, SelectFontDialogBackend> ();
+ RegisterBackend<IPopupWindowBackend, PopupWindowBackend> ();
+ RegisterBackend<IUtilityWindowBackend, UtilityWindowBackend> ();
string typeName = null;
string asmName = null;
diff --git a/Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs b/Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs
index 6cab3d07..c7dfe1c2 100644
--- a/Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs
+++ b/Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs
@@ -46,8 +46,17 @@ namespace Xwt.GtkBackend
WidgetSpacing padding;
Gtk.Alignment alignment;
int arrowDelta;
+ Color backgroundColor;
- public Color BackgroundColor { get; set; }
+ public new Color BackgroundColor {
+ get {
+ return backgroundColor;
+ }
+ set {
+ backgroundColor = value;
+ UpdateBaseColor ();
+ }
+ }
public Xwt.Popover.Position ArrowPosition {
get {
@@ -114,8 +123,19 @@ namespace Xwt.GtkBackend
this.alignment = new Gtk.Alignment (0, 0, 1, 1);
this.alignment.Show ();
this.Add (alignment);
+ }
- OnScreenChanged (null);
+ protected override void OnSupportAlphaChanged ()
+ {
+ UpdateBaseColor ();
+ }
+
+ void UpdateBaseColor ()
+ {
+ if (SupportAlpha)
+ base.BackgroundColor = Drawing.Colors.Transparent.ToCairoColor ();
+ else
+ base.BackgroundColor = BackgroundColor;
}
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
@@ -125,18 +145,10 @@ namespace Xwt.GtkBackend
}
- protected override bool OnDrawn (Context cr)
+ protected override bool OnDraw (Context cr)
{
int w, h;
this.GdkWindow.GetSize (out w, out h);
-
- // We clear the surface with a transparent color if possible
- if (supportAlpha)
- cr.SetSourceRGBA (1.0, 1.0, 1.0, 0.0);
- else
- cr.SetSourceRGB (1.0, 1.0, 1.0);
- cr.Operator = Operator.Source;
- cr.Paint ();
cr.LineWidth = GtkWorkarounds.GetScaleFactor (Content) > 1 ? 2 : 1;
var bounds = new Xwt.Rectangle (cr.LineWidth / 2, cr.LineWidth / 2, w - cr.LineWidth, h - cr.LineWidth);
@@ -153,7 +165,7 @@ namespace Xwt.GtkBackend
DrawTriangle (cr);
// We use it
- if (supportAlpha)
+ if (SupportAlpha)
cr.SetSourceRGBA (0.0, 0.0, 0.0, 0.2);
else
cr.SetSourceRGB (238d / 255d, 238d / 255d, 238d / 255d);
@@ -161,7 +173,7 @@ namespace Xwt.GtkBackend
cr.SetSourceRGBA (BackgroundColor.R, BackgroundColor.G, BackgroundColor.B, BackgroundColor.A);
cr.Fill ();
- return base.OnDrawn (cr);
+ return base.OnDraw (cr);
}
void DrawTriangle (Context ctx)
diff --git a/Xwt.Gtk/Xwt.GtkBackend/PopupWindowBackend.cs b/Xwt.Gtk/Xwt.GtkBackend/PopupWindowBackend.cs
new file mode 100644
index 00000000..1589bcfd
--- /dev/null
+++ b/Xwt.Gtk/Xwt.GtkBackend/PopupWindowBackend.cs
@@ -0,0 +1,63 @@
+//
+// PopupWindowBackend.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using Xwt.Backends;
+
+namespace Xwt.GtkBackend
+{
+ public class PopupWindowBackend : WindowBackend, IPopupWindowBackend
+ {
+ PopupWindow.PopupType windowType;
+
+ public override void Initialize ()
+ {
+ Window = new GtkPopoverWindow (Gtk.WindowType.Toplevel);
+ Window.TypeHint = Gdk.WindowTypeHint.Utility;
+ Window = new GtkPopoverWindow (windowType == PopupWindow.PopupType.Tooltip ? Gtk.WindowType.Popup : Gtk.WindowType.Toplevel);
+
+ switch (windowType) {
+ case PopupWindow.PopupType.Tooltip:
+ Window.TypeHint = Gdk.WindowTypeHint.Tooltip;
+ Window.Decorated = false;
+ break;
+ case PopupWindow.PopupType.Menu:
+ Window.TypeHint = Gdk.WindowTypeHint.PopupMenu;
+ Window.Decorated = false;
+ break;
+ }
+
+ Window.SkipPagerHint = true;
+ Window.SkipTaskbarHint = true;
+ Window.Add (CreateMainLayout ());
+ }
+
+ void IPopupWindowBackend.Initialize (IWindowFrameEventSink sink, PopupWindow.PopupType type)
+ {
+ windowType = type;
+ ((IWindowFrameBackend)this).Initialize (sink);
+ }
+ }
+}
diff --git a/Xwt.Gtk/Xwt.GtkBackend/UtilityWindowBackend.cs b/Xwt.Gtk/Xwt.GtkBackend/UtilityWindowBackend.cs
new file mode 100644
index 00000000..4069c001
--- /dev/null
+++ b/Xwt.Gtk/Xwt.GtkBackend/UtilityWindowBackend.cs
@@ -0,0 +1,43 @@
+//
+// UtilityWindowBackend.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using Xwt.Backends;
+
+namespace Xwt.GtkBackend
+{
+ public class UtilityWindowBackend : WindowBackend, IUtilityWindowBackend
+ {
+ public override void Initialize ()
+ {
+ Window = new GtkPopoverWindow (Gtk.WindowType.Toplevel);
+ Window.TypeHint = Gdk.WindowTypeHint.Utility;
+ Window.SkipPagerHint = true;
+ Window.SkipTaskbarHint = true;
+ Window.Add (CreateMainLayout ());
+ }
+ }
+
+}
diff --git a/Xwt.Gtk/Xwt.GtkBackend/WindowBackend.cs b/Xwt.Gtk/Xwt.GtkBackend/WindowBackend.cs
index cf8e1454..c7d748df 100755
--- a/Xwt.Gtk/Xwt.GtkBackend/WindowBackend.cs
+++ b/Xwt.Gtk/Xwt.GtkBackend/WindowBackend.cs
@@ -27,6 +27,8 @@
using System;
using Xwt.Backends;
+using Xwt.CairoBackend;
+using Xwt.Drawing;
namespace Xwt.GtkBackend
{
@@ -121,6 +123,20 @@ namespace Xwt.GtkBackend
width = RequestedSize.Width;
height = RequestedSize.Height;
}
+
+ Color? backgroundColor;
+
+ Color IWindowBackend.BackgroundColor {
+ get {
+ return backgroundColor ?? Window.GetBackgroundColor ();
+ }
+ set {
+ backgroundColor = value;
+ if (Window is GtkPopoverWindow)
+ ((GtkPopoverWindow)Window).BackgroundColor = value.ToCairoColor ();
+ Window.SetBackgroundColor (value);
+ }
+ }
}
class RootWindowAlignment: Gtk.Alignment, IConstraintProvider
diff --git a/Xwt.WPF/Xwt.WPFBackend/WPFEngine.cs b/Xwt.WPF/Xwt.WPFBackend/WPFEngine.cs
index 9f0e9613..738d07ab 100644
--- a/Xwt.WPF/Xwt.WPFBackend/WPFEngine.cs
+++ b/Xwt.WPF/Xwt.WPFBackend/WPFEngine.cs
@@ -121,6 +121,8 @@ namespace Xwt.WPFBackend
RegisterBackend<IWebViewBackend, WebViewBackend> ();
RegisterBackend<KeyboardHandler, WpfKeyboardHandler> ();
RegisterBackend<ICalendarBackend, CalendarBackend> ();
+ RegisterBackend<IPopupWindowBackend, WindowBackend>();
+ RegisterBackend<IUtilityWindowBackend, WindowBackend>();
}
public override void DispatchPendingEvents()
diff --git a/Xwt.WPF/Xwt.WPFBackend/WindowBackend.cs b/Xwt.WPF/Xwt.WPFBackend/WindowBackend.cs
index bc59f6ab..13a63d53 100644
--- a/Xwt.WPF/Xwt.WPFBackend/WindowBackend.cs
+++ b/Xwt.WPF/Xwt.WPFBackend/WindowBackend.cs
@@ -38,13 +38,14 @@ using Xwt.Backends;
namespace Xwt.WPFBackend
{
- public class WindowBackend : WindowFrameBackend, IWindowBackend
+ public class WindowBackend : WindowFrameBackend, IWindowBackend, IPopupWindowBackend, IUtilityWindowBackend
{
protected Grid rootPanel;
public System.Windows.Controls.Menu mainMenu;
MenuBackend mainMenuBackend;
FrameworkElement widget;
DockPanel contentBox;
+ WindowStyle defaultWindowStyle = WindowStyle.SingleBorderWindow;
public WindowBackend ()
{
@@ -68,6 +69,16 @@ namespace Xwt.WPFBackend
{
base.Initialize ();
Window.Frontend = (Window) Frontend;
+ if (Frontend is UtilityWindow)
+ defaultWindowStyle = WindowStyle.ToolWindow;
+ Decorated = true;
+ }
+
+ public void Initialize(IWindowFrameEventSink sink, PopupWindow.PopupType type)
+ {
+ Initialize ();
+ defaultWindowStyle = WindowStyle.ToolWindow;
+ Decorated = false;
}
// A Grid with a single column, and two rows (menu and child control).
@@ -86,6 +97,18 @@ namespace Xwt.WPFBackend
return grid;
}
+ public override bool Decorated
+ {
+ get { return base.Decorated; }
+ set
+ {
+ base.Decorated = value;
+ if (value)
+ Window.WindowStyle = defaultWindowStyle;
+ Window.AllowsTransparency = Window.WindowStyle == WindowStyle.None && BackgroundColor.Alpha < 1.0;
+ }
+ }
+
public override bool HasMenu {
get { return mainMenu != null; }
}
@@ -188,6 +211,14 @@ namespace Xwt.WPFBackend
{
Window.ResetBorderSize ();
}
+
+ public Xwt.Drawing.Color BackgroundColor {
+ get { return Window.Background.ToXwtColor (); }
+ set {
+ Window.Background = ResPool.GetSolidBrush (value);
+ Window.AllowsTransparency = Window.WindowStyle == WindowStyle.None && value.Alpha < 1.0;
+ }
+ }
}
class WpfWindow : System.Windows.Window
diff --git a/Xwt.WPF/Xwt.WPFBackend/WindowFrameBackend.cs b/Xwt.WPF/Xwt.WPFBackend/WindowFrameBackend.cs
index 5b193bcc..22755f92 100644
--- a/Xwt.WPF/Xwt.WPFBackend/WindowFrameBackend.cs
+++ b/Xwt.WPF/Xwt.WPFBackend/WindowFrameBackend.cs
@@ -117,7 +117,7 @@ namespace Xwt.WPFBackend
get { return eventSink; }
}
- bool IWindowFrameBackend.Decorated {
+ public virtual bool Decorated {
get { return window.WindowStyle != WindowStyle.None; }
set {
window.WindowStyle = value ? WindowStyle.SingleBorderWindow : WindowStyle.None;
@@ -141,7 +141,7 @@ namespace Xwt.WPFBackend
Window.Owner = null;
}
- bool IWindowFrameBackend.Resizable {
+ public virtual bool Resizable {
get {
return resizable;
}
@@ -162,9 +162,9 @@ namespace Xwt.WPFBackend
}
}
- void UpdateResizeMode ()
+ protected void UpdateResizeMode ()
{
- var m = resizable && window.WindowStyle == WindowStyle.SingleBorderWindow ? ResizeMode.CanResize : ResizeMode.NoResize;
+ var m = resizable && window.WindowStyle != WindowStyle.None ? ResizeMode.CanResize : ResizeMode.NoResize;
if (m != window.ResizeMode) {
window.ResizeMode = m;
OnResizeModeChanged ();
diff --git a/Xwt.XamMac/Xwt.Mac/MacEngine.cs b/Xwt.XamMac/Xwt.Mac/MacEngine.cs
index 3af46cf5..ca4ab33a 100644
--- a/Xwt.XamMac/Xwt.Mac/MacEngine.cs
+++ b/Xwt.XamMac/Xwt.Mac/MacEngine.cs
@@ -126,6 +126,8 @@ namespace Xwt.Mac
RegisterBackend <Xwt.Backends.IColorPickerBackend, ColorPickerBackend> ();
RegisterBackend <Xwt.Backends.ICalendarBackend,CalendarBackend> ();
RegisterBackend <Xwt.Backends.ISelectFontDialogBackend, SelectFontDialogBackend> ();
+ RegisterBackend <Xwt.Backends.IPopupWindowBackend, PopupWindowBackend> ();
+ RegisterBackend <Xwt.Backends.IUtilityWindowBackend, PopupWindowBackend> ();
}
public override void RunApplication ()
diff --git a/Xwt.XamMac/Xwt.Mac/PopupWindowBackend.cs b/Xwt.XamMac/Xwt.Mac/PopupWindowBackend.cs
new file mode 100644
index 00000000..7bc77989
--- /dev/null
+++ b/Xwt.XamMac/Xwt.Mac/PopupWindowBackend.cs
@@ -0,0 +1,617 @@
+//
+// PopupWindowBackend.cs
+//
+// Author:
+// Lluis Sanchez <lluis@xamarin.com>
+// Andres G. Aragoneses <andres.aragoneses@7digital.com>
+// Konrad M. Kruczynski <kkruczynski@antmicro.com>
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2011 Xamarin Inc
+// Copyright (c) 2012 7Digital Media Ltd
+// Copyright (c) 2016 Antmicro Ltd
+// Copyright (c) 2017 (c) Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using ObjCRuntime;
+using Xwt.Backends;
+using Xwt.Drawing;
+
+// TODO: Merge back with WindowBackend and reuse code
+
+namespace Xwt.Mac
+{
+ public class PopupWindowBackend : NSPanel, IPopupWindowBackend, IUtilityWindowBackend
+ {
+ WindowBackendController controller;
+ IWindowFrameEventSink eventSink;
+ Window frontend;
+ ViewBackend child;
+ NSView childView;
+ IWindowFrameBackend transientParent;
+ bool sensitive = true;
+ bool isPopup = false;
+ PopupWindow.PopupType windowType;
+
+ public PopupWindowBackend ()
+ {
+ AutorecalculatesKeyViewLoop = true;
+
+ ContentView.AutoresizesSubviews = true;
+ ContentView.Hidden = true;
+
+ // TODO: do it only if mouse move events are enabled in a widget
+ AcceptsMouseMovedEvents = true;
+
+ WillClose += delegate {
+ OnClosed ();
+ };
+
+ }
+
+ public override bool CanBecomeKeyWindow {
+ get {
+ if (!isPopup)
+ return true;
+ return (windowType != PopupWindow.PopupType.Tooltip);
+ }
+ }
+
+ object IWindowFrameBackend.Window {
+ get { return this; }
+ }
+
+ public IntPtr NativeHandle {
+ get { return Handle; }
+ }
+
+ public IWindowFrameEventSink EventSink {
+ get { return (IWindowFrameEventSink)eventSink; }
+ }
+
+ public virtual void InitializeBackend (object frontend, ApplicationContext context)
+ {
+ this.ApplicationContext = context;
+ this.frontend = (Window) frontend;
+ }
+
+ public void Initialize (IWindowFrameEventSink eventSink)
+ {
+ this.eventSink = eventSink;
+ this.isPopup = false;
+ UpdateWindowStyle ();
+ }
+
+ public void Initialize (IWindowFrameEventSink eventSink, PopupWindow.PopupType windowType)
+ {
+ this.isPopup = true;
+ this.eventSink = eventSink;
+ this.windowType = windowType;
+ UpdateWindowStyle ();
+ }
+
+ void UpdateWindowStyle ()
+ {
+ StyleMask |= NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Utility;
+
+ if (!isPopup) {
+ StyleMask |= NSWindowStyle.Resizable;
+ TitleVisibility = NSWindowTitleVisibility.Visible;
+ Level = NSWindowLevel.Floating;
+ FloatingPanel = true;
+ } else {
+ StyleMask |= NSWindowStyle.FullSizeContentView;
+ MovableByWindowBackground = true;
+ TitlebarAppearsTransparent = true;
+ TitleVisibility = NSWindowTitleVisibility.Hidden;
+ this.StandardWindowButton (NSWindowButton.CloseButton).Hidden = true;
+ this.StandardWindowButton (NSWindowButton.MiniaturizeButton).Hidden = true;
+ this.StandardWindowButton (NSWindowButton.ZoomButton).Hidden = true;
+
+ if (windowType == PopupWindow.PopupType.Tooltip)
+ // NSWindowLevel.ScreenSaver overlaps menus, this allows showing tooltips above menus
+ Level = NSWindowLevel.ScreenSaver;
+ else
+ Level = NSWindowLevel.PopUpMenu;
+ }
+ }
+
+ public override void MouseExited (NSEvent theEvent)
+ {
+ if (windowType == PopupWindow.PopupType.Tooltip)
+ Visible = false;
+ base.MouseExited (theEvent);
+ }
+
+ public ApplicationContext ApplicationContext {
+ get;
+ private set;
+ }
+
+ public object NativeWidget {
+ get {
+ return this;
+ }
+ }
+
+ public string Name { get; set; }
+
+ public void Present ()
+ {
+ Visible = true;
+ MakeKeyAndOrderFront (MacEngine.App);
+ }
+
+ public bool Visible {
+ get {
+ return IsVisible;
+ }
+ set {
+ ContentView.Hidden = !value; // handle shown/hidden events
+ IsVisible = value;
+
+ if (transientParent != null) {
+ var win = transientParent as NSWindow ?? ApplicationContext.Toolkit.GetNativeWindow (transientParent) as NSWindow;
+ if (win != null) {
+ if (value)
+ win.AddChildWindow (this, NSWindowOrderingMode.Above);
+ else
+ win.RemoveChildWindow (this);
+ }
+ }
+ }
+ }
+
+ public double Opacity {
+ get { return AlphaValue; }
+ set { AlphaValue = (float)value; }
+ }
+
+ Color? backgroundColor;
+ public new Color BackgroundColor {
+ get {
+ if (backgroundColor.HasValue)
+ return backgroundColor.Value;
+ return base.BackgroundColor.ToXwtColor ();
+ }
+ set {
+ backgroundColor = value;
+ base.BackgroundColor = value.ToNSColor ();
+ IsOpaque = false;
+ }
+ }
+
+ public bool Sensitive {
+ get {
+ return sensitive;
+ }
+ set {
+ sensitive = value;
+ if (child != null)
+ child.UpdateSensitiveStatus (child.Widget, sensitive);
+ }
+ }
+
+ public bool HasFocus {
+ get {
+ return IsKeyWindow;
+ }
+ }
+
+ public bool FullScreen {
+ get {
+ if (MacSystemInformation.OsVersion < MacSystemInformation.Lion)
+ return false;
+
+ return (StyleMask & NSWindowStyle.FullScreenWindow) != 0;
+
+ }
+ set {
+ if (MacSystemInformation.OsVersion < MacSystemInformation.Lion)
+ return;
+
+ if (value != ((StyleMask & NSWindowStyle.FullScreenWindow) != 0))
+ ToggleFullScreen (null);
+ }
+ }
+
+ object IWindowFrameBackend.Screen {
+ get {
+ return Screen;
+ }
+ }
+
+ #region IWindowBackend implementation
+ void IBackend.EnableEvent (object eventId)
+ {
+ if (eventId is WindowFrameEvent) {
+ var @event = (WindowFrameEvent)eventId;
+ switch (@event) {
+ case WindowFrameEvent.BoundsChanged:
+ DidResize += HandleDidResize;
+ DidMove += HandleDidResize;
+ break;
+ case WindowFrameEvent.Hidden:
+ EnableVisibilityEvent (@event);
+ this.WillClose += OnWillClose;
+ break;
+ case WindowFrameEvent.Shown:
+ EnableVisibilityEvent (@event);
+ break;
+ case WindowFrameEvent.CloseRequested:
+ WindowShouldClose = OnShouldClose;
+ break;
+ }
+ }
+ }
+
+ void OnWillClose (object sender, EventArgs args) {
+ OnHidden ();
+ }
+
+ bool OnShouldClose (NSObject ob)
+ {
+ return closePerformed = RequestClose ();
+ }
+
+ internal bool RequestClose ()
+ {
+ bool res = true;
+ ApplicationContext.InvokeUserCode (() => res = eventSink.OnCloseRequested ());
+ return res;
+ }
+
+ protected virtual void OnClosed ()
+ {
+ if (!disposing)
+ ApplicationContext.InvokeUserCode (eventSink.OnClosed);
+ }
+
+ bool closePerformed;
+
+ bool IWindowFrameBackend.Close ()
+ {
+ closePerformed = true;
+ if ((StyleMask & NSWindowStyle.Titled) != 0 && (StyleMask & NSWindowStyle.Closable) != 0)
+ PerformClose(this);
+ else
+ Close ();
+ return closePerformed;
+ }
+
+ bool VisibilityEventsEnabled ()
+ {
+ return eventsEnabled != WindowFrameEvent.BoundsChanged;
+ }
+ WindowFrameEvent eventsEnabled = WindowFrameEvent.BoundsChanged;
+
+ NSString HiddenProperty {
+ get { return new NSString ("hidden"); }
+ }
+
+ void EnableVisibilityEvent (WindowFrameEvent ev)
+ {
+ if (!VisibilityEventsEnabled ()) {
+ ContentView.AddObserver (this, HiddenProperty, NSKeyValueObservingOptions.New, IntPtr.Zero);
+ }
+ if (!eventsEnabled.HasFlag (ev)) {
+ eventsEnabled |= ev;
+ }
+ }
+
+ public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context)
+ {
+ if (keyPath.ToString () == HiddenProperty.ToString () && ofObject.Equals (ContentView)) {
+ if (ContentView.Hidden) {
+ if (eventsEnabled.HasFlag (WindowFrameEvent.Hidden)) {
+ OnHidden ();
+ }
+ } else {
+ if (eventsEnabled.HasFlag (WindowFrameEvent.Shown)) {
+ OnShown ();
+ }
+ }
+ }
+ }
+
+ void OnHidden () {
+ ApplicationContext.InvokeUserCode (delegate ()
+ {
+ eventSink.OnHidden ();
+ });
+ }
+
+ void OnShown () {
+ ApplicationContext.InvokeUserCode (delegate ()
+ {
+ eventSink.OnShown ();
+ });
+ }
+
+ void DisableVisibilityEvent (WindowFrameEvent ev)
+ {
+ if (eventsEnabled.HasFlag (ev)) {
+ eventsEnabled ^= ev;
+ if (!VisibilityEventsEnabled ()) {
+ ContentView.RemoveObserver (this, HiddenProperty);
+ }
+ }
+ }
+
+ void IBackend.DisableEvent (object eventId)
+ {
+ if (eventId is WindowFrameEvent) {
+ var @event = (WindowFrameEvent)eventId;
+ switch (@event) {
+ case WindowFrameEvent.BoundsChanged:
+ DidResize -= HandleDidResize;
+ DidMove -= HandleDidResize;
+ break;
+ case WindowFrameEvent.Hidden:
+ this.WillClose -= OnWillClose;
+ DisableVisibilityEvent (@event);
+ break;
+ case WindowFrameEvent.Shown:
+ DisableVisibilityEvent (@event);
+ break;
+ }
+ }
+ }
+
+ void HandleDidResize (object sender, EventArgs e)
+ {
+ OnBoundsChanged ();
+ }
+
+ protected virtual void OnBoundsChanged ()
+ {
+ LayoutWindow ();
+ ApplicationContext.InvokeUserCode (delegate {
+ eventSink.OnBoundsChanged (((IWindowBackend)this).Bounds);
+ });
+ }
+
+ void IWindowBackend.SetChild (IWidgetBackend child)
+ {
+ if (this.child != null) {
+ ViewBackend.RemoveChildPlacement (this.child.Widget);
+ this.child.Widget.RemoveFromSuperview ();
+ childView = null;
+ }
+ this.child = (ViewBackend) child;
+ if (child != null) {
+ childView = ViewBackend.GetWidgetWithPlacement (child);
+ ContentView.AddSubview (childView);
+ LayoutWindow ();
+ childView.AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable;
+ }
+ }
+
+ public virtual void UpdateChildPlacement (IWidgetBackend childBackend)
+ {
+ var w = ViewBackend.SetChildPlacement (childBackend);
+ LayoutWindow ();
+ w.AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable;
+ }
+
+ bool IWindowFrameBackend.Decorated {
+ get {
+ return (StyleMask & NSWindowStyle.Titled) != 0;
+ }
+ set {
+ if (value)
+ StyleMask |= NSWindowStyle.Titled;
+ else
+ StyleMask &= ~(NSWindowStyle.Titled | NSWindowStyle.Borderless);
+ HasShadow = value;
+ }
+ }
+
+ bool IWindowFrameBackend.ShowInTaskbar {
+ get {
+ return false;
+ }
+ set {
+ }
+ }
+
+ void IWindowFrameBackend.SetTransientFor (IWindowFrameBackend window)
+ {
+ if (transientParent == window)
+ return;
+
+ transientParent = window;
+
+ if (!isPopup)
+ Level = window == null ? NSWindowLevel.Floating : NSWindowLevel.ModalPanel;
+
+ if (ParentWindow != null)
+ ParentWindow.RemoveChildWindow (this);
+
+ // add to parent now, only if already visible
+ if (window != null && IsVisible) {
+ var win = window as NSWindow ?? ApplicationContext.Toolkit.GetNativeWindow (window) as NSWindow;
+ if (win != null)
+ win.AddChildWindow (this, NSWindowOrderingMode.Above);
+ }
+ }
+
+ bool IWindowFrameBackend.Resizable {
+ get {
+ return (StyleMask & NSWindowStyle.Resizable) != 0;
+ }
+ set {
+ if (value)
+ StyleMask |= NSWindowStyle.Resizable;
+ else
+ StyleMask &= ~NSWindowStyle.Resizable;
+ }
+ }
+
+ public void SetPadding (double left, double top, double right, double bottom)
+ {
+ LayoutWindow ();
+ }
+
+ void IWindowFrameBackend.Move (double x, double y)
+ {
+ var r = MacDesktopBackend.FromDesktopRect (new Rectangle (x, y, Frame.Width, Frame.Height));
+ r = FrameRectFor (r);
+ SetFrameOrigin (r.Location);
+ }
+
+ void IWindowFrameBackend.SetSize (double width, double height)
+ {
+ var cr = ContentRectFor (Frame);
+ if (width == -1)
+ width = cr.Width;
+ if (height == -1)
+ height = cr.Height;
+ var r = FrameRectFor (new CGRect ((nfloat)cr.X, (nfloat)cr.Y, (nfloat)width, (nfloat)height));
+ SetFrame (r, true);
+ LayoutWindow ();
+ }
+
+ Rectangle IWindowFrameBackend.Bounds {
+ get {
+ var b = ContentRectFor (Frame);
+ var r = MacDesktopBackend.ToDesktopRect (b);
+ return new Rectangle ((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height);
+ }
+ set {
+ var r = MacDesktopBackend.FromDesktopRect (value);
+ var fr = FrameRectFor (r);
+ SetFrame (fr, true);
+ }
+ }
+
+ public void SetMainMenu (IMenuBackend menu)
+ {
+ var m = (MenuBackend) menu;
+ m.SetMainMenuMode ();
+ NSApplication.SharedApplication.Menu = m;
+
+// base.Menu = m;
+ }
+
+ #endregion
+
+ static Selector closeSel = new Selector ("close");
+ #if MONOMAC
+ static Selector retainSel = new Selector("retain");
+ #endif
+
+ bool disposing, disposed;
+
+ protected override void Dispose(bool disposing)
+ {
+ if (!disposed && disposing)
+ {
+ this.disposing = true;
+ try
+ {
+ if (VisibilityEventsEnabled() && ContentView != null)
+ ContentView.RemoveObserver(this, HiddenProperty);
+
+ // HACK: Xamarin.Mac/MonoMac limitation: no direct way to release a window manually
+ // A NSWindow instance will be removed from NSApplication.SharedApplication.Windows
+ // only if it is being closed with ReleasedWhenClosed set to true but not on Dispose
+ // and there is no managed way to tell Cocoa to release the window manually (and to
+ // remove it from the active window list).
+ // see also: https://bugzilla.xamarin.com/show_bug.cgi?id=45298
+ // WORKAROUND:
+ // bump native reference count by calling DangerousRetain()
+ // base.Dispose will now unref the window correctly without crashing
+ DangerousRetain();
+ // tell Cocoa to release the window on Close
+ ReleasedWhenClosed = true;
+ // Close the window (Cocoa will do its job even if the window is already closed)
+ Messaging.void_objc_msgSend (this.Handle, closeSel.Handle);
+ } finally {
+ this.disposing = false;
+ this.disposed = true;
+ }
+ }
+ if (controller != null) {
+ controller.Dispose ();
+ controller = null;
+ }
+ base.Dispose (disposing);
+ }
+
+ public void DragStart (TransferDataSource data, DragDropAction dragAction, object dragImage, double xhot, double yhot)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void SetDragSource (string[] types, DragDropAction dragAction)
+ {
+ }
+
+ public void SetDragTarget (string[] types, DragDropAction dragAction)
+ {
+ }
+
+ public virtual void SetMinSize (Size s)
+ {
+ var b = ((IWindowBackend)this).Bounds;
+ if (b.Size.Width < s.Width)
+ b.Width = s.Width;
+ if (b.Size.Height < s.Height)
+ b.Height = s.Height;
+
+ if (b != ((IWindowBackend)this).Bounds)
+ ((IWindowBackend)this).Bounds = b;
+
+ var r = FrameRectFor (new CGRect (0, 0, (nfloat)s.Width, (nfloat)s.Height));
+ MinSize = r.Size;
+ }
+
+ public void SetIcon (ImageDescription icon)
+ {
+ }
+
+ public virtual void GetMetrics (out Size minSize, out Size decorationSize)
+ {
+ minSize = decorationSize = Size.Zero;
+ }
+
+ public virtual void LayoutWindow ()
+ {
+ LayoutContent (ContentView.Frame);
+ }
+
+ public void LayoutContent (CGRect frame)
+ {
+ if (child != null) {
+ frame.X += (nfloat) frontend.Padding.Left;
+ frame.Width -= (nfloat) (frontend.Padding.HorizontalSpacing);
+ frame.Y += (nfloat) frontend.Padding.Top;
+ frame.Height -= (nfloat) (frontend.Padding.VerticalSpacing);
+ childView.Frame = frame;
+ }
+ }
+ }
+}
+
diff --git a/Xwt.XamMac/Xwt.Mac/WindowBackend.cs b/Xwt.XamMac/Xwt.Mac/WindowBackend.cs
index d900cfd5..2fc1bde8 100644
--- a/Xwt.XamMac/Xwt.Mac/WindowBackend.cs
+++ b/Xwt.XamMac/Xwt.Mac/WindowBackend.cs
@@ -34,6 +34,7 @@ using CoreGraphics;
using Foundation;
using ObjCRuntime;
using Xwt.Backends;
+using Xwt.Drawing;
namespace Xwt.Mac
{
@@ -133,6 +134,15 @@ namespace Xwt.Mac
set { AlphaValue = (float)value; }
}
+ Color IWindowBackend.BackgroundColor {
+ get {
+ return BackgroundColor.ToXwtColor ();
+ }
+ set {
+ BackgroundColor = value.ToNSColor ();
+ }
+ }
+
public bool Sensitive {
get {
return sensitive;
diff --git a/Xwt.XamMac/Xwt.XamMac.csproj b/Xwt.XamMac/Xwt.XamMac.csproj
index 0446afbd..414e435f 100644
--- a/Xwt.XamMac/Xwt.XamMac.csproj
+++ b/Xwt.XamMac/Xwt.XamMac.csproj
@@ -133,6 +133,7 @@
<Compile Include="Xwt.Mac\SelectFontDialogBackend.cs" />
<Compile Include="Xwt.Mac\NSApplicationInitializer.cs" />
<Compile Include="Xwt.Mac\GtkQuartz.cs" />
+ <Compile Include="Xwt.Mac\PopupWindowBackend.cs" />
</ItemGroup>
<Import Project="..\BuildHelpers.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/Xwt/Xwt.Backends/IPopupWindowBackend.cs b/Xwt/Xwt.Backends/IPopupWindowBackend.cs
new file mode 100644
index 00000000..49597f9d
--- /dev/null
+++ b/Xwt/Xwt.Backends/IPopupWindowBackend.cs
@@ -0,0 +1,33 @@
+//
+// IPopupWindowBackend.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 (c) Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+namespace Xwt.Backends
+{
+ public interface IPopupWindowBackend : IWindowBackend
+ {
+ void Initialize (IWindowFrameEventSink sink, PopupWindow.PopupType type);
+ }
+}
diff --git a/Xwt/Xwt.Backends/IUtilityWindowBackend.cs b/Xwt/Xwt.Backends/IUtilityWindowBackend.cs
new file mode 100644
index 00000000..7668d4c0
--- /dev/null
+++ b/Xwt/Xwt.Backends/IUtilityWindowBackend.cs
@@ -0,0 +1,32 @@
+//
+// IUtilityWindowBackend.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Xwt.Backends
+{
+ public interface IUtilityWindowBackend : IWindowBackend
+ {
+ }
+}
diff --git a/Xwt/Xwt.Backends/IWindowBackend.cs b/Xwt/Xwt.Backends/IWindowBackend.cs
index 066404a6..0d2a16a0 100755
--- a/Xwt/Xwt.Backends/IWindowBackend.cs
+++ b/Xwt/Xwt.Backends/IWindowBackend.cs
@@ -26,11 +26,13 @@
using System;
using Xwt;
+using Xwt.Drawing;
namespace Xwt.Backends
{
public interface IWindowBackend: IWindowFrameBackend, IChildPlacementHandler
{
+ Color BackgroundColor { get; set; }
void SetChild (IWidgetBackend child);
void SetMainMenu (IMenuBackend menu);
void SetPadding (double left, double top, double right, double bottom);
diff --git a/Xwt/Xwt.csproj b/Xwt/Xwt.csproj
index b618d4ca..a3780b36 100644
--- a/Xwt/Xwt.csproj
+++ b/Xwt/Xwt.csproj
@@ -346,6 +346,9 @@
<Compile Include="Xwt.Backends\IComboBoxCellViewFrontend.cs" />
<Compile Include="Xwt.Backends\IDispatcherBackend.cs" />
<Compile Include="Xwt\ITranslationCatalog.cs" />
+ <Compile Include="Xwt.Backends\IPopupWindowBackend.cs" />
+ <Compile Include="Xwt\UtilityWindow.cs" />
+ <Compile Include="Xwt.Backends\IUtilityWindowBackend.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup />
diff --git a/Xwt/Xwt/PopupWindow.cs b/Xwt/Xwt/PopupWindow.cs
index 7ff3c38b..80c28357 100644
--- a/Xwt/Xwt/PopupWindow.cs
+++ b/Xwt/Xwt/PopupWindow.cs
@@ -3,6 +3,7 @@
//
// Author:
// Lluis Sanchez <lluis@xamarin.com>
+// Vsevolod Kukol <sevoku@microsoft.com>
//
// Copyright (c) 2011 Xamarin Inc
//
@@ -23,14 +24,59 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-using System;
+
+using Xwt.Backends;
namespace Xwt
{
- public class PopupWindow
+ [BackendType (typeof (IPopupWindowBackend))]
+ public class PopupWindow : Window
{
- public PopupWindow ()
+ public enum PopupType
+ {
+ Tooltip,
+ Menu
+ }
+
+ readonly PopupType type;
+
+ public PopupType Type { get { return type; } }
+
+ public PopupWindow () : this (PopupType.Tooltip)
+ {
+ }
+
+ public PopupWindow (PopupType type) : base (0)
{
+ this.type = type;
+ switch (type) {
+ case PopupType.Tooltip:
+ case PopupType.Menu:
+ ShowInTaskbar = false;
+ InitialLocation = WindowLocation.CenterParent;
+ Resizable = false;
+ break;
+ }
+ }
+
+ protected new class WindowBackendHost : Window.WindowBackendHost
+ {
+ new PopupWindow Parent { get { return (PopupWindow)base.Parent; } }
+
+ protected override void OnBackendCreated ()
+ {
+ base.OnBackendCreated ();
+ ((IPopupWindowBackend)Backend).Initialize (this, Parent.Type);
+ }
+ }
+
+ protected override BackendHost CreateBackendHost ()
+ {
+ return new WindowBackendHost ();
+ }
+
+ IPopupWindowBackend Backend {
+ get { return (IPopupWindowBackend)BackendHost.Backend; }
}
}
}
diff --git a/Xwt/Xwt/UtilityWindow.cs b/Xwt/Xwt/UtilityWindow.cs
new file mode 100644
index 00000000..885127b1
--- /dev/null
+++ b/Xwt/Xwt/UtilityWindow.cs
@@ -0,0 +1,57 @@
+//
+// UtilityWindow.cs
+//
+// Author:
+// Vsevolod Kukol <sevoku@microsoft.com>
+//
+// Copyright (c) 2017 Microsoft Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using Xwt.Backends;
+namespace Xwt
+{
+ [BackendType (typeof (IUtilityWindowBackend))]
+ public class UtilityWindow : Window
+ {
+ public UtilityWindow () : base (0)
+ {
+ }
+
+ protected new class WindowBackendHost : Window.WindowBackendHost
+ {
+ new UtilityWindow Parent { get { return (UtilityWindow)base.Parent; } }
+
+ protected override void OnBackendCreated ()
+ {
+ base.OnBackendCreated ();
+ ((IUtilityWindowBackend)Backend).Initialize (this);
+ }
+ }
+
+ protected override BackendHost CreateBackendHost ()
+ {
+ return new WindowBackendHost ();
+ }
+
+ IUtilityWindowBackend Backend {
+ get { return (IUtilityWindowBackend)BackendHost.Backend; }
+ }
+ }
+}
diff --git a/Xwt/Xwt/WidgetSpacing.cs b/Xwt/Xwt/WidgetSpacing.cs
index 0c120bcd..4a3ddac5 100644
--- a/Xwt/Xwt/WidgetSpacing.cs
+++ b/Xwt/Xwt/WidgetSpacing.cs
@@ -44,8 +44,10 @@ namespace Xwt
/// </summary>
[TypeConverter (typeof(WidgetSpacingValueConverter))]
[ValueSerializer (typeof(WidgetSpacingValueSerializer))]
- public struct WidgetSpacing
+ public struct WidgetSpacing : IEquatable<WidgetSpacing>
{
+ public static WidgetSpacing Zero = new WidgetSpacing ();
+
static public implicit operator WidgetSpacing (double value)
{
return new WidgetSpacing (value, value, value, value);
@@ -99,6 +101,12 @@ namespace Xwt
get { return Top + Bottom; }
}
+ public bool IsZero {
+ get {
+ return ((Left == 0) && (Right == 0) && (Top == 0) && (Bottom == 0));
+ }
+ }
+
/// <summary>
/// Get the spacing of a widget for the specified orientation.
/// </summary>
@@ -111,6 +119,41 @@ namespace Xwt
else
return Left + Right;
}
+
+ // Equality
+ public override bool Equals (object o)
+ {
+ if (!(o is WidgetSpacing))
+ return false;
+
+ return (this == (WidgetSpacing)o);
+ }
+
+ public bool Equals (WidgetSpacing other)
+ {
+ return this == other;
+ }
+
+ public override int GetHashCode ()
+ {
+ unchecked {
+ var hash = Left.GetHashCode ();
+ hash = (hash * 397) ^ Right.GetHashCode ();
+ hash = (hash * 397) ^ Top.GetHashCode ();
+ hash = (hash * 397) ^ Bottom.GetHashCode ();
+ return hash;
+ }
+ }
+
+ public static bool operator == (WidgetSpacing s1, WidgetSpacing s2)
+ {
+ return ((s1.Left == s2.Left) && (s1.Right == s2.Right) && (s1.Top == s2.Top) && (s1.Bottom == s2.Bottom));
+ }
+
+ public static bool operator != (WidgetSpacing s1, WidgetSpacing s2)
+ {
+ return !(s1 == s2);
+ }
}
diff --git a/Xwt/Xwt/Window.cs b/Xwt/Xwt/Window.cs
index bb1dbbce..4b2d1a39 100644
--- a/Xwt/Xwt/Window.cs
+++ b/Xwt/Xwt/Window.cs
@@ -26,7 +26,7 @@
using System;
using Xwt.Backends;
-
+using Xwt.Drawing;
namespace Xwt
{
@@ -46,10 +46,15 @@ namespace Xwt
{
return new WindowBackendHost ();
}
+
+ public Window () : this (12)
+ {
+ }
- public Window ()
+ internal Window (WidgetSpacing initialPadding)
{
- Padding = 12;
+ if (!initialPadding.IsZero)
+ Padding = initialPadding;
}
IWindowBackend Backend {
@@ -61,6 +66,11 @@ namespace Xwt
set { initialLocation = value; }
}
+ public Color BackgroundColor {
+ get { return Backend.BackgroundColor; }
+ set { Backend.BackgroundColor = value; }
+ }
+
public WidgetSpacing Padding {
get { return padding; }
set {