-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathCustomWindow.rb
69 lines (58 loc) · 3.67 KB
/
CustomWindow.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# Description: This is the implementation file for the CustomWindow class, which is our subclass of NSWindow. We need to subclass
# NSWindow in order to configure the window properly in #initWithContentRect(contentRect, styleMask:aStyle, backing:bufferingType, defer:flag)
# to have a custom shape and be transparent. We also override the #mouseDown and #mouseDragged metohds,
# to allow for dragging the window by clicking on its content area (since it doesn't have a title bar to drag).
class CustomWindow < NSWindow
attr_accessor :initialLocation
# In Interface Builder we set CustomWindow to be the class for our window, so our own initializer is called here.
# the original method is being extended but still called thanks to the `super` call
def initWithContentRect(contentRect, styleMask:aStyle, backing:bufferingType, defer:flag)
# Call NSWindow's version of this function, but pass in the all-important value of NSBorderlessWindowMask
#for the styleMask so that the window doesn't have a title bar
result = super(contentRect, NSBorderlessWindowMask, NSBackingStoreBuffered, false)
# Set the background color to clear so that (along with the setOpaque call below) we can see through the parts
# of the window that we're not drawing into
result.setBackgroundColor(NSColor.clearColor)
# This next line pulls the window up to the front on top of other system windows. This is how the Clock app behaves;
# generally you wouldn't do this for windows unless you really wanted them to float above everything.
result.setLevel(NSStatusWindowLevel)
# Let's start with no transparency for all drawing into the window
result.setAlphaValue(1.0)
# but let's turn off opaqueness so that we can see through the parts of the window that we're not drawing into
result.setOpaque(false)
# and while we're at it, make sure the window has a shadow, which will automatically be the shape of our custom content.
result.setHasShadow(true)
result
end
# Custom windows that use the NSBorderlessWindowMask can't become key by default. Therefore, controls in such windows
# won't ever be enabled by default. Thus, we override this method to change that.
def canBecomeKeyWindow
true
end
# Once the user starts dragging the mouse, we move the window with it. We do this because the window has no title
# bar for the user to drag (so we have to implement dragging ourselves)
# (overriding original method)
def mouseDragged(theEvent)
screen_frame = NSScreen.mainScreen.frame
window_frame = self.frame
current_location = self.convertBaseToScreen(self.mouseLocationOutsideOfEventStream)
# grab the current global mouse location; we could just as easily get the mouse location
# in the same way as we do in -mouseDown:
new_origin = NSPoint.new((current_location.x - @initialLocation.x), (current_location.y - @initialLocation.y))
# Don't let the window get dragged up under the menu bar
if((new_origin.y + window_frame.size.height) > (screen_frame.origin.y + screen_frame.size.height))
new_origin.y = screen_frame.origin.y + (screen_frame.size.height - window_frame.size.height)
end
# go ahead and move the window to the new location
self.setFrameOrigin(new_origin)
end
# We start tracking the a drag operation here when the user first clicks the mouse,
# to establish the initial location.
def mouseDown(theEvent)
window_frame = frame
# grab the mouse location in global coordinates
@initialLocation = convertBaseToScreen(theEvent.locationInWindow)
@initialLocation.x -= window_frame.origin.x
@initialLocation.y -= window_frame.origin.y
end
end