How to drag window from an element inside WKWebView? - macos

I want to create a "frameless" window (HiddenTitleBarWindowStyle). Inside this window there will a WKWebView spanning from edge to edge. Is there a way to have an element inside the webview to be the drag handle for the entire window?
Electron has something like this and I'm wondering how to implement it in SwiftUI.
https://www.electronjs.org/docs/latest/api/frameless-window#draggable-region
I tried making the window movable by the background (isMovableByWindowBackground = true). However, the WKWebView seems to stop the event propagation.

Related

NSWindow - detect movement by drag vs animation

I have an NSWindow on which I set movableByWindowBackground = YES so that it can be moved by dragging it's contents. I then implement it's windowDidMove delegate method so I can detect when it moves, but at times I'm also animating this window. I'd like to detect when the window is moved due to a mouse drag vs an animation. Is there an easy way to do this?

How do I display a custom view modally, within an existing window?

I am trying to build a UI with a main window that displays some content, and sometimes slides-in a modal view from the right edge of the window. Interaction with the main content must be blocked while the modal is open; however, clicking the main content should close the modal. Here's a mockup:
Please note the user should see only one window. That is, the modal should be nested inside the main window.
I have very little experience with AppKit and Cocoa in general. My approach so far has been to structure my UI like this:
Root region (NSView)
-> MainRegion (NSView)
-> ModalRegion (NSView; toggle hidden and animate the left edge)
and then add subviews to MainRegion and ModalRegion to display content. The problem is that ModalRegion doesn't absorb input events.
What's the AppKit way to build this kind of UI? I mainly just need to know about how the view hierarchy should be shaped and how to block/absorb input events. I think I can figure out the animations myself. Also, the app targets macOS 10.8+, but answers for more recent versions would be helpful, as well.
It’s not really macOS like UI but there are two approaches you could use. In both cases you would use a transparent view to cover the main window and to dismiss the modal view in case of a mouse click. If you need a shadow overlapping the main window as shown in your mockup you will need to use a window attached to the main window as a child window. If this is not the case it would be enough to work with a view which is attached to the contentView of the main window.
All the best.

Discard mouse events on NSWindow based on click position

Let's say I have a floating, borderless, circular NSWindow.
It is circular because the content view simply draws a red circle.
That content view needs to be layer-backed ([contentView setWantsLayer:YES]), because I'm applying CoreAnimations on it, e.g., animated scaling.
Usually, the clickable area of a NSWindow is defined by the transparency of the pixels of the content view. However, once the content view of a NSWindow becomes layer-backed, transparent areas will also receive clicks, unfortunately.
In my case, this is a serious problem, because I only want to receive clicks within the radius. But now, a click within the rect of the window, but beyond the circle radius, will activate the window (and thus, the entire app), which it shouldn't. Also the window is draggable via the corner of its content view.
My initial thought was to implement [NSWindow sendEvent:] in a subclass and check whether the click was performed within the radius, using [theEvent locationInWindow]. I thought I could simply discard the event, if it's beyond the radius, by not calling [super sendEvent:theEvent] then. This however did not work: I noticed, that the mouseDown:; window method is called even before the sendEvent:; method.
I've search a lot but the only idea I found, was to have a proxy like non-layer backed NSWindow on top of the window, which delegates clicks conditionally, but this led to unpredictable UI behavior.
Do you guys have any idea, how to solve it?
So after a few weeks, I came to the following results:
A) Proxy window:
Make use of a non layer-backed proxy window, which is placed on top of the target window as a child window. The proxy window has the same shape, as the target window, and since it is not layer-backed, it will properly receive and ignore events. The proxy window delegates all events to the target window by overwriting sendEvent:. The target window is set to ignore all mouse events.
B) Global Mouse Pointer observation:
Install both a global and local event monitor for NSMouseMovedMask|NSLeftMouseDraggedMask events using addGlobalMonitorForEventsMatchingMask and addLocalMonitorForEventsMatchingMask. The event monitors disable and enable ignoring mouse events on all registered target windows based on the current global mouse position. In the case of circular windows, the distance between the mouse pointer and every target window must be calculated.
Both approaches work well in generally, but I've been experiencing some unpredictable misbehaviors of the child window approach (where the child window is 'out-of-sync' of its parent's position).
UPDATE: Both approaches have some significant disadvantages:
In A), the proxy window sometimes may be out of sync and may be placed slightly off the actual window.
In B), the event monitor has a big impact on battery life while moving the mouse, even if the app is not the front-most application.
If you want to Discard mouseDown event based on position you can use the:
CGPathContainsPoint(path,transform,point,eoFill):Bool
Setup your path to match your graphics. Circles, ellipses, rectangles, triangles or paths and even compositional paths (paths with holes in them).

How to implement Lion style swipe and slide away animation

I am wanting to implement history navigation in my app that mimics the slide away animation found in Safari on Lion and in XCode where a top view slides away at the speed of swipe to reveal the view underneath it.
I was looking for pointers on how to do this. I know how to detect the swipe. I assume I could implement the animation via a CALayer animation slide transition on the top view revealing a view underneath it. Has anybody else done this and can offer some further pointers?
It's a new NSEvent method, -trackSwipeEventWithOptions:.... You should call it from within your regular scroll/swipe event handler, whenever you decide the gesture should begin. Unfortunately it doesn't automatically handle the page animations — it just gives you updates with the gesture amount, and you have to do the animations yourself (using layers or views or somesuch). You'll probably want to save images of each page so you can animate them around during a gesture.

Can Ext-GWT animate the window minimize-down event?

Looking at the web desktop sample for Ext-JS I see that when a window is minimized or restored, that there is an animation where a transparent rectangle shrinks down to the task bar or grows up to the window location.
When I look at the same demo for Ext-GWT there is no animation: the window just vanishes and reappears.
Is there a way to turn this animation on for Ext-GWT, and what is the code to do it.
I think you can do it. The catch is that you have to
catch the minimize event
replace your rendered window with a proxy
simultaneously move and resize your proxy
replace your final proxy with the button on the dock bar
I'd consider following the extjs implementation as a guide.
The fact that it isn't represented as a demo suggests that it takes quite a bit of work to put it together.

Resources