public static IDisposable AddMenuTemporarily(FrameworkElement element, Optional <Menu> menu, IScheduler dispatcher)
        {
            if (!menu.HasValue)
            {
                element.ContextMenu = null;
                return(Disposable.Empty);
            }

            element.ContextMenu = new System.Windows.Controls.ContextMenu();

            var dispose = Disposable.Empty;

            element.ContextMenu.IsVisibleChanged += (sender, e) =>
            {
                if ((bool)e.NewValue)
                {
                    dispose.Dispose();
                    element.ContextMenu.Items.Clear();
                    dispose = WindowsMenuBuilder.PopulateContextMenu(menu.Value, element.ContextMenu, null, dispatcher);
                }
                else
                {
                    dispose.Dispose();
                    element.ContextMenu.Items.Clear();
                    dispose = Disposable.Empty;
                }
            };

            return(Disposable.Create(() => dispose.Dispose()));
        }
Esempio n. 2
0
        public static System.Windows.Window Initialize(Window model)
        {
            var dispatcher = Fusion.Application.MainThread;

            var windowSubject = new BehaviorSubject <Optional <WindowWithOverlays> >(Optional.None());

            var menu = new System.Windows.Controls.Menu();

            DockPanel.SetDock(menu, Dock.Top);

            var contentContainer = new Canvas()
            {
                // This is needed for native overlays to work
                ClipToBounds = true,
            };
            var panel = new DockPanel()
            {
                LastChildFill = true,
                Children      =
                {
                    menu,
                    contentContainer
                }
            };

            var ret = new FancyWindow(model.Style == WindowStyle.Regular || model.Style == WindowStyle.Fat)
            {
                Content = panel
            };

            var focused = new Subject <Unit>();

            model.Focused.Execute.Sample(focused).Subscribe(c => c());
            ret.Activated += (sender, args) => focused.OnNext(Unit.Default);

            var availableSize = DataBinding
                                .ObservableFromNativeEvent <SizeChangedEventArgs>(contentContainer, "SizeChanged")
                                .Select(e => e.NewSize.ToFusion())
                                .Replay(1);

            availableSize.Connect();

            var content = model.Content;
            //.SetNativeWindow(windowSubject)
            //.SetDensity(ret.DensityFactor);
            var transize = availableSize.Transpose();

            content.Mount(
                new MountLocation.Mutable
            {
                AvailableSize = transize,
                NativeFrame   = ObservableMath.RectangleWithSize(transize),
                IsRooted      = Observable
                                .FromEventPattern <DependencyPropertyChangedEventArgs>(ret, "IsVisibleChanged")
                                .Select(arg => ret.IsVisible)
                                .Replay(1).RefCount(),
            });

            content.BindNativeProperty(dispatcher, "Background", model.Background, color =>
                                       menu.Background = ret.Background = new SolidColorBrush(color.ToColor()));

            content.BindNativeProperty(dispatcher, "Foreground", model.Foreground, color =>
                                       menu.Foreground = ret.Foreground = new SolidColorBrush(color.ToColor()));

            content.BindNativeProperty(dispatcher, "BorderBrush", model.Border.Brush, color =>
                                       ret.BorderBrush = new SolidColorBrush(color.ToColor()));

            content.BindNativeProperty(dispatcher, "BorderThickness", model.Border.Thickness, thickness =>
                                       ret.BorderThickness = new System.Windows.Thickness(thickness));


            Fusion.Application.MainThread
            .InvokeAsync(() => content.NativeHandle)
            .ToObservable().OfType <UIElement>()
            .Subscribe(nativeContent =>
                       contentContainer.Children.Add(nativeContent));

            var windowState =
                model.State
                .Or(Property.Default <Optional <WindowState> >())
                .Or(WindowState.Normal)
                .AutoInvalidate()
                .PreventFeedback();

            windowState.Subscribe(state => dispatcher.InvokeAsync(() =>
                                                                  ret.WindowState = state == WindowState.Normal ? System.Windows.WindowState.Normal : System.Windows.WindowState.Maximized));

            ret.StateChanged += (sender, args) =>
                                windowState.Write(
                ret.WindowState == System.Windows.WindowState.Maximized
                                                ? WindowState.Maximized
                                                : WindowState.Normal);

            model.Size.Do(
                maybeSize =>
            {
                var size = maybeSize
                           .Or(Size.Create <Points>(Double.NaN, Double.NaN))
                           .AutoInvalidate(TimeSpan.FromSeconds(2))
                           .PreventFeedback();

                bool setByUs = false;

                size.Subscribe(s => dispatcher.Schedule(() =>
                {
                    setByUs       = true;
                    ret.Width     = (float)s.Width;
                    var newHeight = s.Height + (TitleBarHeight + menu.ActualHeight);
                    ret.Height    = (float)newHeight;
                    setByUs       = false;
                }));

                ret.SizeChanged += (s, a) =>
                {
                    if (setByUs)
                    {
                        return;
                    }

                    var contentSize = new Size <Points>(a.NewSize.Width, a.NewSize.Height - (TitleBarHeight + menu.ActualHeight));
                    size.Write(contentSize);
                };
            });

            model.Position.Do(
                maybePosition =>
            {
                var pos = maybePosition
                          .Or(new Point <Points>(double.NaN, double.NaN))
                          .AutoInvalidate(TimeSpan.FromSeconds(2))
                          .PreventFeedback();
                // TODO: ConnectWhile() ?

                bool setByUs = false;

                pos.Subscribe(p => dispatcher.Schedule(() =>
                {
                    setByUs  = true;
                    ret.Left = p.X;
                    ret.Top  = p.Y;
                    setByUs  = false;
                }));

                Fusion.Application.MainThread.Schedule(() =>
                {
                    ret.LocationChanged += (s, args) =>
                    {
                        if (setByUs)
                        {
                            return;
                        }

                        var sender = s as FancyWindow;
                        if (sender == null)
                        {
                            return;
                        }

                        pos.Write(new Point <Points>(sender.Left, sender.Top));
                    };
                });
            });

            model.TopMost.Do(topMost =>
                             topMost.Subscribe(t => dispatcher.Schedule(() =>
            {
                ret.Topmost = t;
                ret.Show();
            })));

            model.Size.Do(s =>
                          s.IsReadOnly.Subscribe(isReadOnly => dispatcher.Schedule(() =>
            {
                if (isReadOnly)
                {
                    ret.ResizeMode            = ResizeMode.NoResize;
                    ret.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                }
            })));


            var closed = new Subject <Unit>();

            ret.Closed += (s, a) => closed.OnNext(Unit.Default);
            model.Closed.Execute.Sample(closed).Subscribe(e => e());

            model.Title.Subscribe(title => dispatcher.Schedule(() =>
            {
                ret.Title = model.HideTitle ? "" : title;
            }));

            model.Menu.Do(m => WindowsMenuBuilder.Populate(m, menu, ret, dispatcher));

            DataBinding
            .ObservableFromNativeEvent <EventArgs>(ret, "Loaded")
            .Subscribe(_ => windowSubject.OnNext(ret));

            DataBinding
            .ObservableFromNativeEvent <EventArgs>(ret, "LayoutUpdated")
            .Select(a => PresentationSource.FromVisual(ret))
            .DistinctUntilChanged()
            .Subscribe(
                presentation =>
            {
                if (presentation == null)
                {
                    return;
                }

                var winHandle = new WindowInteropHelper(ret).Handle;
                WindowPlacement.SetPlacement(winHandle, WindowPlacement.GetPlacement(winHandle));
            });

            ret.Closing += (s, a) =>
            {
                model.Closed.Execute.Take(1).Subscribe(e => e());
                ExitIfLastVisibleWindow(ret);
            };

            ret.IsVisibleChanged += (s, a) =>
            {
                if (ret.IsVisible == false)
                {
                    ExitIfLastVisibleWindow(ret);
                }
            };

            return(ret);
        }