2006年 12月 01日

OSX Drag Picture

スクリーンショットを対話的にとるとき、マウスでドラッグして選択するのがあるけど、あれってどうやってやるんだろうって考えてた。
マウスイベントをキャプチャーして……とか面倒くさそうだなぁとか思ってたけど全然違う方法で実装できそうだ。

require 'osx/cocoa'
include OSX

class SelectionView < NSView
	attr_accessor :delegate

	def drawRect(rect)
		NSColor.colorWithCalibratedRed(0, :green, 0, :blue, 0, :alpha, 0.1).set
		NSRectFill(bounds)

		if @start && @end
			NSColor.colorWithCalibratedRed(0.5, :green, 0.5, :blue, 0.5, :alpha, 0.5).set
			NSRectFill(calc_rect)
		end
	end

	def mouseDown(event)
		@start = NSEvent.mouseLocation
	end

	def mouseDragged(event)
		@end = NSEvent.mouseLocation
		setNeedsDisplay(true)
	end

	def mouseUp(event)
		@end = NSEvent.mouseLocation
		delegate.windowShouldClose(nil)
		window.close
	end

	def calc_rect
		x = [@start.x , @end.x].min
		y = [@start.y , @end.y].min
		w = (@start.x - @end.x).abs
		h = (@start.y - @end.y).abs
		[x, y, w, h]
	end
end

class TEST < NSObject
	def applicationDidFinishLaunching(aNotification)
		size = NSScreen.mainScreen.frame.size
		rect = [0, 0, size.width, size.height]
		@window = NSWindow.alloc.initWithContentRect(rect,
		                                  :styleMask, NSBorderlessWindowMask,
		                                    :backing, NSBackingStoreBuffered,
		                                      :defer, 0)
		@window.setDelegate(self)
		@window.setOpaque(0)
		@window.setHasShadow(0)
		@window.setLevel(1000) # NSScreenSaverWindowLevel

		@view = SelectionView.alloc.initWithFrame(rect)
		@view.delegate = self
		@window.setContentView(@view)

		@window.makeKeyAndOrderFront(nil)
		@window.orderFrontRegardless
	end

	def windowShouldClose(sender)
		p @view.calc_rect
		exit
		true
	end
end

$App = NSApplication.sharedApplication
$App.setDelegate(TEST.alloc.init)
$App.run

スクリーンと同じサイズのできるだけ透明なウィンドウを作ってあげてそいつでイベントうけとる。