public bool Run (ExceptionDialogData data) { using (var alert = new NSAlert { AlertStyle = NSAlertStyle.Critical }) { alert.Icon = NSApplication.SharedApplication.ApplicationIconImage; alert.MessageText = data.Title ?? GettextCatalog.GetString ("Error"); if (!string.IsNullOrEmpty (data.Message)) { alert.InformativeText = data.Message; } List<AlertButton> buttons = null; if (data.Buttons != null && data.Buttons.Length > 0) buttons = data.Buttons.Reverse ().ToList (); if (buttons != null) { foreach (var button in buttons) { var label = button.Label; if (button.IsStockButton) label = Gtk.Stock.Lookup (label).Label; label = label.Replace ("_", ""); //this message seems to be a standard Mac message since alert handles it specially if (button == AlertButton.CloseWithoutSave) label = GettextCatalog.GetString ("Don't Save"); alert.AddButton (label); } } if (data.Exception != null) { var scrollSize = new SizeF (400, 130); float spacing = 4; string title = GettextCatalog.GetString ("View details"); string altTitle = GettextCatalog.GetString ("Hide details"); var buttonFrame = new RectangleF (0, 0, 0, 0); var button = new NSButton (buttonFrame) { BezelStyle = NSBezelStyle.Disclosure, Title = "", AlternateTitle = "", }; button.SetButtonType (NSButtonType.OnOff); button.SizeToFit (); var label = new MDClickableLabel (title) { Alignment = NSTextAlignment.Left, }; label.SizeToFit (); button.SetFrameSize (new SizeF (button.Frame.Width, Math.Max (button.Frame.Height, label.Frame.Height))); label.SetFrameOrigin (new PointF (button.Frame.Width + 5, button.Frame.Y)); var text = new MyTextView (new RectangleF (0, 0, float.MaxValue, float.MaxValue)) { HorizontallyResizable = true, }; text.TextContainer.ContainerSize = new SizeF (float.MaxValue, float.MaxValue); text.TextContainer.WidthTracksTextView = true; text.InsertText (new NSString (data.Exception.ToString ())); text.Editable = false; var scrollView = new NSScrollView (new RectangleF (PointF.Empty, SizeF.Empty)) { HasHorizontalScroller = true, HasVerticalScroller = true, }; var accessory = new NSView (new RectangleF (0, 0, scrollSize.Width, button.Frame.Height)); accessory.AddSubview (scrollView); accessory.AddSubview (button); accessory.AddSubview (label); alert.AccessoryView = accessory; button.Activated += delegate { float change; if (button.State == NSCellStateValue.On) { change = scrollSize.Height + spacing; label.StringValue = altTitle; scrollView.Hidden = false; scrollView.Frame = new RectangleF (PointF.Empty, scrollSize); scrollView.DocumentView = text; } else { change = -(scrollSize.Height + spacing); label.StringValue = title; scrollView.Hidden = true; scrollView.Frame = new RectangleF (PointF.Empty, SizeF.Empty); } var f = accessory.Frame; f.Height += change; accessory.Frame = f; var lf = label.Frame; lf.Y += change; label.Frame = lf; var bf = button.Frame; bf.Y += change; button.Frame = bf; label.SizeToFit (); var panel = (NSPanel) alert.Window; var pf = panel.Frame; pf.Height += change; pf.Y -= change; panel.SetFrame (pf, true, true); //unless we assign the icon again, it starts nesting old icon into the warning icon alert.Icon = NSApplication.SharedApplication.ApplicationIconImage; alert.Layout (); }; label.OnMouseUp += (sender, e) => button.PerformClick (e.Event); } int result = alert.RunModal () - (int)NSAlertButtonReturn.First; data.ResultButton = buttons != null ? buttons [result] : null; GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow); } return true; }
public bool Run (AlertDialogData data) { using (var alert = new NSAlert ()) { alert.Window.Title = data.Title ?? BrandingService.ApplicationName; if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) { alert.AlertStyle = NSAlertStyle.Critical; } else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Warning) { alert.AlertStyle = NSAlertStyle.Warning; } else { //if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) { alert.AlertStyle = NSAlertStyle.Informational; } //FIXME: use correct size so we don't get horrible scaling? if (!string.IsNullOrEmpty (data.Message.Icon)) { var pix = ImageService.GetPixbuf (data.Message.Icon, Gtk.IconSize.Dialog); byte[] buf = pix.SaveToBuffer ("tiff"); unsafe { fixed (byte* b = buf) { alert.Icon = new NSImage (NSData.FromBytes ((IntPtr)b, (uint)buf.Length)); } } } else { //for some reason the NSAlert doesn't pick up the app icon by default alert.Icon = NSApplication.SharedApplication.ApplicationIconImage; } alert.MessageText = data.Message.Text; alert.InformativeText = data.Message.SecondaryText ?? ""; var buttons = data.Buttons.Reverse ().ToList (); for (int i = 0; i < buttons.Count - 1; i++) { if (i == data.Message.DefaultButton) { var next = buttons[i]; for (int j = buttons.Count - 1; j >= i; j--) { var tmp = buttons[j]; buttons[j] = next; next = tmp; } break; } } foreach (var button in buttons) { var label = button.Label; if (button.IsStockButton) label = Gtk.Stock.Lookup (label).Label; label = label.Replace ("_", ""); //this message seems to be a standard Mac message since alert handles it specially if (button == AlertButton.CloseWithoutSave) label = GettextCatalog.GetString ("Don't Save"); alert.AddButton (label); } NSButton[] optionButtons = null; if (data.Options.Count > 0) { var box = new MDBox (LayoutDirection.Vertical, 2, 2); optionButtons = new NSButton[data.Options.Count]; for (int i = data.Options.Count - 1; i >= 0; i--) { var option = data.Options[i]; var button = new NSButton () { Title = option.Text, Tag = i, State = option.Value? NSCellStateValue.On : NSCellStateValue.Off, }; button.SetButtonType (NSButtonType.Switch); optionButtons[i] = button; box.Add (new MDAlignment (button, true) { XAlign = LayoutAlign.Begin }); } box.Layout (); alert.AccessoryView = box.View; } NSButton applyToAllCheck = null; if (data.Message.AllowApplyToAll) { alert.ShowsSuppressionButton = true; applyToAllCheck = alert.SuppressionButton; applyToAllCheck.Title = GettextCatalog.GetString ("Apply to all"); } // Hack up a slightly wider than normal alert dialog. I don't know how to do this in a nicer way // as the min size constraints are apparently ignored. var frame = ((NSPanel) alert.Window).Frame; ((NSPanel) alert.Window).SetFrame (new RectangleF (frame.X, frame.Y, Math.Max (frame.Width, 600), frame.Height), true); alert.Layout (); bool completed = false; if (data.Message.CancellationToken.CanBeCanceled) { data.Message.CancellationToken.Register (delegate { alert.InvokeOnMainThread (() => { if (!completed) { NSApplication.SharedApplication.AbortModal (); } }); }); } if (!data.Message.CancellationToken.IsCancellationRequested) { int result = alert.RunModal () - (int)NSAlertButtonReturn.First; completed = true; if (result >= 0 && result < buttons.Count) { data.ResultButton = buttons [result]; } else { data.ResultButton = null; } } if (data.ResultButton == null || data.Message.CancellationToken.IsCancellationRequested) { data.SetResultToCancelled (); } if (optionButtons != null) { foreach (var button in optionButtons) { var option = data.Options[button.Tag]; data.Message.SetOptionValue (option.Id, button.State != 0); } } if (applyToAllCheck != null && applyToAllCheck.State != 0) data.ApplyToAll = true; GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow); } return true; }
public bool Run (AlertDialogData data) { using (var alert = new NSAlert ()) { if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) { alert.AlertStyle = NSAlertStyle.Critical; } else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Warning) { alert.AlertStyle = NSAlertStyle.Warning; } else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) { alert.AlertStyle = NSAlertStyle.Informational; } //FIXME: use correct size so we don't get horrible scaling? if (!string.IsNullOrEmpty (data.Message.Icon)) { var pix = ImageService.GetPixbuf (data.Message.Icon, Gtk.IconSize.Dialog); byte[] buf = pix.SaveToBuffer ("tiff"); unsafe { fixed (byte* b = buf) { alert.Icon = new NSImage (NSData.FromBytes ((IntPtr)b, (uint)buf.Length)); } } } alert.MessageText = data.Message.Text; alert.InformativeText = data.Message.SecondaryText ?? ""; var buttons = data.Buttons.Reverse ().ToList (); for (int i = 0; i < buttons.Count - 1; i++) { if (i == data.Message.DefaultButton) { var next = buttons[i]; for (int j = buttons.Count - 1; j >= i; j--) { var tmp = buttons[j]; buttons[j] = next; next = tmp; } break; } } foreach (var button in buttons) { var label = button.Label; if (button.IsStockButton) label = Gtk.Stock.Lookup (label).Label; label = label.Replace ("_", ""); //this message seems to be a standard Mac message since alert handles it specially if (button == AlertButton.CloseWithoutSave) label = GettextCatalog.GetString ("Don't Save"); alert.AddButton (label); } NSButton[] optionButtons = null; if (data.Options.Count > 0) { var box = new MDBox (LayoutDirection.Vertical, 2, 2); optionButtons = new NSButton[data.Options.Count]; for (int i = data.Options.Count - 1; i >= 0; i--) { var option = data.Options[i]; var button = new NSButton () { Title = option.Text, Tag = i, State = option.Value? NSCellStateValue.On : NSCellStateValue.Off, }; button.SetButtonType (NSButtonType.Switch); optionButtons[i] = button; box.Add (new MDAlignment (button, true) { XAlign = LayoutAlign.Begin }); } box.Layout (); alert.AccessoryView = box.View; } NSButton applyToAllCheck = null; if (data.Message.AllowApplyToAll) { alert.ShowsSuppressionButton = true; applyToAllCheck = alert.SuppressionButton; applyToAllCheck.Title = GettextCatalog.GetString ("Apply to all"); } alert.Layout (); int result = alert.RunModal () - (int)NSAlertButtonReturn.First; data.ResultButton = buttons [result]; if (optionButtons != null) { foreach (var button in optionButtons) { var option = data.Options[button.Tag]; data.Message.SetOptionValue (option.Id, button.State != 0); } } if (applyToAllCheck != null && applyToAllCheck.State != 0) data.ApplyToAll = true; GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow); } return true; }