ShowModalWithin on macOS - now centered, used to drop down from the top

Since a few macOS versions, SheetWindows no longer drop down from the top of the main window; instead, they appear in the center of the screen. This means that using ShowModalWithin is not the same experience it used to be.

In particular, I have used sheet dialog windows to drop down for user Confirm / Reject actions, in situations where the user is looking at something in the main window. This works when the dialog drops down from the top, when what the user is looking at in the main window is below the dialog. Now that the dialog appears in the middle, it covers up what the user is supposed to be looking at. So this change by Apple has ruined the UI for these dialogs in my apps. I need a way to fix this. Some ideas:

  • reposition the dialog (not possible?)
  • make the dialog transparent (not possible?)
  • somehow roll my own (I really think I shouldn’t have to do that)

Any help? Am I missing something?

No, you’re not missing something. All you can do it send a report to Apple and dream that they will change it. Frankly that isn’t going to happen.

Sheets are too useful to go without, they are window modal, rather than application modal. No other window based option that you may put together is going to replicate that. The best you can do it put an application modal window to do the job. However, that will block every window on your application, which frankly isn’t worth doing. You loose the connection to the document etc.

The only other option I can think of is to have a container control that would sit in front of other controls on the window, but that comes with all sorts of additional problems. You would have to somehow manage your own modality between your fake ‘sheet’ and the rest of the window. Not only for mouse events but also keyboard events.

It doesn’t sound like a good idea and would make your application very non-standard.

Another option comes to mind. Instead of dialog boxes that say “Are you sure you want to do that”, you could implement an undo mechanism so they can go back if they don’t like the result. Personally, I find “are you sure?” dialogs somewhat annoying, especially Firefox’s new “Are you sure you want to quit” message. Obviously, permanent, destructive changes need some sort of confirmation. Such as “Document changed, are you sure you want to discard changes and close?” type things need confirmation.

Hm, I wonder … is there a way to get a reference to the window of a Xojo MessageDialog? Then at least I could use Window.TransparencyMBS and make it semi-transparent so the user can see what’s behind it.

Not according to the Sheet window API. I’ve tried changing the background color of sheet windows before and it makes no difference, such changes do not function.

Oh I agree, and I’ve got an Undo engine. The problem situations are where the dialog is for showing a preview the user is supposed to approve. So the user has to be able to see it to know whether they want to approve it.

Then include an area at the bottom of the window that shows and includes a checkbox or buttons, within the main window.

Yes. I was just thinking of that, or something like Photoshop’s little floating “X, check” boxes.

Rather than attempting to make it look like a window, why not simply make it part of the window. You can show or hide it when required. You could even animate the appearance.

If you have GraffitiSuite then take a look at the GraffitiModal. It’s a fantastic piece of code that lets you use essentially Container controls as fade-in modals, and it’s cross-platform too (although the animations admittedly look far better on MacOS).

Here it is in action on one of my projects:

Edit: I should add that the dimming of the background window is optional, it sounds like in your applicatio you want the user to be able to see the window.

1 Like

Right. The window is basically a big canvas anyway. I was just trying to avoid drawing a dialog into what the user is evaluating. This will take more work than I’d like, but I suppose ultimately it will be the most realiable x-plat alternative.

Make a container control with your confirmation requirements. Add that to the window along side your canvas. Show / Hide the container as needed, shrinking / growing the canvas when needed.

Yep, I’ll be doing something like that. Thank you for the help :wink:

1 Like

Thank you, but I don’t have GraffitiSuite. Also, your modal window looks nice, but it’s in the center like the new dialogs on macOS, which is what I’m trying to avoid. The solution seems to be that I’ll have to use something other than a dialog, which may be better for the user anyway.

1 Like

You may have a look at the bug tracker where bugs have been reported for a feature request that finally has been implemented.

1 Like

If you make your own dialog, this is possible. It is tricky from Xojo, and a lot of work IIRC, but there is an Apple API that you can override to control where a sheet window will appear.

What would be better, but still not supported by Xojo would be a Popover. I made a class in my non-API 2.0 compatible App Kit that did just this, Confirm Delete.

Nope, I had a feature request for this… But ended re-inventing the wheel (writing my own to use Apple’s API so I could control it better than the options Xojo exposed).

On macOS the MessageDialog is an NSAlert.

Alternatively, what Ian says and use a canvas with a container control, the canvas is to capture mouse events. With declares you can tap into the Apple shadow engine so you can make it look like a sheet and position it where never you want.

Information about GraffitiModal

Minor things like this can always be added with a Feature Request, and this one just has been added. If you ever do decide to give GraffitiSuite a try, it’ll be there:

Added: GraffitiModalInstance.Placements enumeration. LeftTop, LeftMiddle, LeftBottom, CenterTop, CenterMiddle, CenterBottom, RightTop, RightMiddle, RightBottom
Added: GraffitiModalInstance.Placement = GraffitiModalInstance.Placements.CenterMiddle property.
Added: GraffitiModalInstance.PlacementBoundaryMargin as Integer = 10 property. Determines distance from the window's edge when using an outside placement.

There are also many different animation options:

  • Fade
  • SlideUp
  • SlideDown
  • SlideLeft
  • SlideRight
  • Grow
  • Reveal
  • RollHorizontal
  • RollVertical
  • WindowShade
  • Doors
  • None

And a ton of other properties to customize the experience, like easings so you can create bounce effects.

Documentation

You likely will need to roll your own using a Container and positioning it where you want. If you don’t want the user to interact with the outside elements of the window, then you’ll need to put it in a canvas and handle the mouse events. I think, however, there’s a bug there that still allows some interactions with some controls, like hover effects.

1 Like

I’m working on this, and the biggest problem isn’t so much making a UI substitue for the dialog. It’s the fact that not using a dialog changes the way my methods have to be written. In pseudocode:

// here’s code before the dialog that does a lot of stuff
’ blah blah
// then here’s the dialog
if ShowMessageDialog( “Confirm or Reject?” ) = “Confirm” then
// here’s more code after confirming
else
// reject code
end if

That obviously doesn’t work any more. I have to break up methods into parts and pass information around or store properties. Not saying my previous way of working was the greatest design, but it was easy and it worked. Redesigning because it no longer works is a big headache.

Surely you just put the ‘do it’ code into the Action event of the confirm button. The Reject code goes in the Cancel button…

Well, more or less. I tend not to put code in the events but have the events call methods. But the point is, whatever infomation was living in the method before the dialog isn’t avaliable to those buttons. I have to totally refactor the code. When it’s all in one method, there’s no need to store information or send it anywhere. It’s just making things more complicated.