diff options
author | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-06 21:17:16 +0300 |
---|---|---|
committer | Vsevolod Kukol <sevoku@microsoft.com> | 2017-03-06 21:17:16 +0300 |
commit | de0715a3fc95dfa778e09659eb3fa413a68eb656 (patch) | |
tree | ec966a4e4fc5696742946f3e785a24d66f1d5f15 | |
parent | 1e937afc891f680880e0ae5118ee9a70fa739bab (diff) | |
parent | ad878125a61299c290f1689e3c247a48821fbf2d (diff) |
Merge remote-tracking branch 'origin/add-popup-window' into monodevelop-native-popupsmonodevelop-native-popups
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 { |