SimpleCapβ版をリリースします。
SimpleCap-B1.zip
α版リリースからずいぶん経ってしまいました。前回と大きく違うのは QuickPanelをやめて SimpleViewerを搭載したこと。
使った方で感想・要望・バグ報告があれば是非教えてください。
(方法はコメントでもメールでもどちらでも良いです)
*スクリーンショット
メニューバーから操作
SimpleViewer
範囲指定
プリファレンス
*α版を使っていた方へ
設定(プリファレンス)の互換性はありますが、設定関係で挙動がおかしい場合は plistファイルを削除してみて下さい。
ファイル:ホームディレクトリ > ライブラリ > Preferences > com.xcatsan.SimpleCap.plist
- - - -
次は3月中の本リリースを予定しています。
(SimpleCapはフリーウェアとして公開する予定です)
リリースまでは基本的に新機能追加は行わず、バグ取り、ブラッシュアップや公開用ホームページ作り、そしてアイコン作りに専念する予定です。
2009年2月28日土曜日
SimpleCap β版リリース
2009年2月27日金曜日
SimpleViewer - 繰り返しキャプチャを追加
2009年2月26日木曜日
2009年2月25日水曜日
簡易アイコン画像生成ユーティリティ IconCreator
MacOSXで標準にあるアイコン画像を SimpleCapで利用できないか検討中。Widgetのアイコンを Widgetを表す目的で利用するなら恐らく問題ないだろう。加工は縮小のみ。
この目的で小さなユーティリティプログラムを作成した。
実行可能アプリ: IconCreator.app.zip
(ユニバーサルバイナリ)
ソースコード:IconCreator.zip
起動するとこんな画面が表示される。
適当にファイルをドラッグ&ドロップすると、そのアイコン画像を取り出して 16x16, 32x32 のサイズで表示する。
"create"ボタンを押すとそれぞれの大きさの PNG画像をデスクトップ上に作成する。
プレビューで見てみたところ。
- - - -
30分そこらで、こんなちょっとしたツールが作れてしまう。あいかわらず MacOSX開発環境は生産性が高い(楽しいし)。
2009年2月24日火曜日
プリファレンス調整中
あーでもない、こーでもないと調整中。
- - - -
Safari4 Beta が公開された。
JavaScriptが高速化された他、サムネイルやカバーフローなどビジュアル的にも派手な機能が加わっている。
早速試してみたいが仕事上 Safari3 も必要なためどうしたものか。共存できるのだろうか。
2009年2月23日月曜日
QuickConfig に画像フォーマット追加
こんな感じ。
メニューの排他制御は以前紹介した方法を利用した。
Cocoaの日々 - Cocoa Bindingsを使ったメニューの排他選択
- - - -
何かと忙しい今日このごろ。
β版を出せるのかが微妙。。
2009年2月22日日曜日
ドラッグ&ドロップ(6)ウィンドウの移動
以前ウィンドウの移動を抑止したが、画像以外の余白部分のドラッグであればウィンドウ移動にしたい。NSView#mouseDownCanMoveWindowが使えそうに見えたがどうもうまくいかず、結局余白部分のヒットテスト&自前ウィンドウ移動で対応した。
(参考)Cocoabuilder - Re: Conditional mouseDownCanMoveWindow for NSView?
擬似コードはこんな感じ。
- (void)mouseDown:(NSEvent *)theEvent
{
if (画像ヒットテスト) {
// ドラッグ処理
} else {
// ウィンドウ移動処理
NSWindow *window = [self window];
NSPoint origin = [window frame].origin;
NSPoint old_p = [window convertBaseToScreen:[theEvent locationInWindow]];
while ((theEvent = [window nextEventMatchingMask:NSLeftMouseDraggedMask|NSLeftMouseUpMask]) && ([theEvent type] != NSLeftMouseUp)) {
NSPoint new_p = [window convertBaseToScreen:[theEvent locationInWindow]];
origin.x += new_p.x - old_p.x;
origin.y += new_p.y - old_p.y;
[window setFrameOrigin:origin];
old_p = new_p;
}
}
}
例えば下の図の場合、中心の画像上でマウスを押せば画像のドラッグ&ドロップになり、その周りの黒い余白をドラッグすればウィンドウの移動となる。
2009年2月21日土曜日
xcodeリファクタリングはnibも対象
2009年2月20日金曜日
ドラッグ&ドロップ(5)ドロップ先を増やす
ファインダだけでなく他のアプリへもドラッグ&ドロップできるようにしよう。
ペーストボード(NSPasteboard)へ他のデータタイプも登録する。
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
[pboard declareTypes:[NSArray arrayWithObjects:NSFilesPromisePboardType, NSFilenamesPboardType, NSTIFFPboardType, nil] owner:self];
[pboard setPropertyList:[NSArray arrayWithObject:[filename pathExtension]]
forType:NSFilesPromisePboardType];
[pboard setData:[image TIFFRepresentation] forType:NSTIFFPboardType];
[pboard setPropertyList:[NSArray arrayWithObject:filename]
forType:NSFilenamesPboardType];
これで大抵のアプリへドラッグ&ドロップできるようになった。
なお Mail.app はファインダと同じくNSFilesPromisePboardTypeを使っていて添付ファイル用のフォルダへコピーすることを期待しているようだ。ドロップ時に呼出される namesOfPromisedFilesDroppedAtDestination: の引数を見ると、コピー先のURL指定はこんな感じだった。
file://localhost/private/var/folders/0d/0dNdrhYNHnqjC2KaQLPHu++++TI/-Tmp-/com.apple.mail.drag-T0x710f70.tmp.4L3Dui/
ファインダ向けのコードそのまま(ファイルを指定フォルダへコピーする)でうまく動いた。
2009年2月19日木曜日
ドラッグ&ドロップ(4)マウスカーソルにプラスマークを
ファインダへのドロップ時にマウスカーソルにプラスマーク(+)をつけたい。これは draggingSourceOperationMaskForLocal: を使うと簡単にできる。
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
return NSDragOperationCopy;
}
このメソッドはドラッグ&ドロップ開始で使った dragImage:at:offset:event:pasteboard:source:slideBack: を呼出したビューに対してコールバックされる。ドラッグ中、ドラッグ先が変化するたびに呼出される。戻り値は NSDragOperation で定義されていて、今回は NSDragOperationCopy を返すようにした。
さて実行してみよう。以前はマウスカーソルにプラスマークが付いていなかった。
それがこうなる。
2009年2月18日水曜日
ドラッグ&ドロップ(3)ファインダへドロップ
基本的な部分ができたのでファインダへのドロップ処理を実装する。
これは随分前に検証していたので簡単にできた。
詳細は下記を参照の事。
スクラップブックその10 - 画像をファインダへドラッグ&ドロップする
SimpleViewerで画像をつかんでデスクトップ(ファインダ)へドロップすると
ファイルがコピーされる。
2009年2月17日火曜日
ドラッグ&ドロップ(2)ドラッグ画像の加工
ドラッグ画像を加工する。前回は画像の透明度と大きさは現物のままだった。
まずドラッグ画像を半透明にする。これは #dragImage:at:offset:event:pasteboard:source:slideBack: へ渡すNSImageを半透明に加工すれば良い。
NSImage *dragged_image = [[[NSImage alloc] initWithSize:_image.size] autorelease];
[dragged_image lockFocus];
[_image compositeToPoint:NSZeroPoint
operation:NSCompositeSourceOver
fraction:0.5f];
[dragged_image unlockFocus];
こうなる。
次は大きさの調整。原寸大のままなのでこれを表示倍率に合わせた大きさに修正する。
前回は compositeToPoint:operation:fraction: を使っていた。
[_image compositeToPoint:NSZeroPoint
operation:NSCompositeSourceOver
fraction:0.8f];
これを drawInRect:fromRect:operation:fraction: に変える。
[_image drawInRect:NSMakeRect(0, 0, size.width, size.height)
fromRect:NSMakeRect(0, 0, _image.size.width, _image.size.height)
operation:NSCompositeSourceOver
fraction:0.5f];
描画先範囲 と描画元範囲を指定することで縮小された画像を描画することができる。
するとこうなる。
2009年2月16日月曜日
ドラッグ&ドロップ(1)ドラッグ開始
β版前最後の機能としてSimpleViewerにドラッグ&ドロップを実装する。SimpleViewer上の画像をつかんでファインダなどの他のアプリへ渡せるようにしよう。
まずはドラッグ開始から。これは NSViewのメソッド NSView#dragImage:at:offset:event:pasteboard:source:slideBack: を使うと簡単にできる。このメソッドを mouseDwon: に実装すればマウスボタンを押した時にドラッグが開始される。
- (void)mouseDown:(NSEvent *)theEvent
{
[self dragImage:dragged_image
at:NSMakePoint(0, 0)
offset:NSZeroSize
event:theEvent
pasteboard:pboard
source:self
slideBack:YES];
}
dragged_image にはとりあえず表示中の画像をそのまま渡しておく。
こんな感じ。
なお SimpleViewer(NSPanel)はデフォルトでウィンドウのドラッグ移動が有効になっているので、今回のドラッグと動作がバッティングしてうまくいかない。画像のドラッグが始まると同時にウィンドウの移動が行われてしまる。そこでNSWindow#setMovableByWindowBackground:を使いドラッグ時ウィンドウ移動の動作を切っておく。
SimpleViewerPanel.m
[self setMovableByWindowBackground:NO];
ただこれはこれで不便だ。もう一工夫必要だな。
2009年2月15日日曜日
QuickConfig(3) SimpleViewerでもQuickConfig
2009年2月14日土曜日
2009年2月13日金曜日
QuickConfig - プリファレンス設定をその場で
時々キャプチャ直前にプリファレンスの設定を変えたい場合がある。頻繁に設定を変える場合もいちいちプリファレンスを開くのがおっくう。要望も出たので対応することにする。何か名前があると開発しやすいので Quick Config(クイックコンフィグ)と名付けてみた。
ユーザインターフェイスだが、例えば範囲選択なら枠線が表示された状態で設定ができると良い。そこで専用のボタンを用意して、これを押すと設定メニューが開くようにしてみた。こんな感じ。
メニューの内容はプリファレンスで設定できるものと同じ。
少し独特なインターフェイスになってしまった。他のボタンの動作と違ってメニューが開くことを伝えたいので白点を加えてみた。
実装は Interface Builderであらかじめメニューを用意しておき、コードからこれを参照してポップアップさせる。
[NSMenu popUpContextMenu:[_app_controller selectionConfigMenu] withEvent:event forView:view];
メニューの各値はおなじみの Cococa Bindings で UserDefaultsと紐づけてある。あいわらず楽だ。
2009年2月12日木曜日
ウィンドウを前へ、前へ、一番前へ
プリファンスウィンドウを開くと一番上に来ないことがある。キャプチャ中に設定を変えようと呼出すが現れない。他のウィンドウに埋もれて出てこないこともたびたび。
不便と思いつつなんとなく放っておいたが表示個所を見直してみた。今はプリファレンスを開くのに NSWindow#makeKeyAndOrderFront: を使っている。
[_window makeKeyAndOrderFront:self];
このメソッドでは弱くて?他のウィンドウに負けてしまうようだ。
もう少しマニュアルを眺めていると NSWindow#orderWindow:relativeTo: というメソッドを見つけた。これを代わりに使ってみよう。
[_window orderWindow:NSWindowAbove relativeTo:0];
マニュアルによれば上記引数の組み合わせで一番上に来るらしい。
結果は○。一番上に表示されるようになった。
さてこれで解決と思いきや、範囲選択中にプリファレンスを開くとまた埋もれたまま一番上に出てこない。
今度は同じアプリ内での順番が問題になっているようだ。再び #makeKeyAndOrderFront: を持ち出し、#orderWindow:relativeTo: と一緒に使う。
[_window makeKeyAndOrderFront:self];
[_window orderWindow:NSWindowAbove relativeTo:0];
よさそうだ。ただ使っているとやっぱり上に来ないケースがある。どうもアプリがアクティブにならないと駄目なようだ。
そこで最終手段?である。NSApplication#activateIgnoringOtherApps: を使う。
[NSApp activateIgnoringOtherApps:YES];
[_window makeKeyAndOrderFront:self];
これは強力で試した限りでは必ず一番上に来た。難点は他のアプリからアクティブ状態を奪い取ってしまうことだが、そもそもプリファレンスで設定を行えばそうなるのでこれは問題ないか。
しばらくこれで使ってみることにしよう。
2009年2月11日水曜日
Cocoa Bindingsを使ったメニューの排他選択
前回 SimpleViewerにコンテキストメニューを追加したが、この中で背景は Black, Checkboard, White の3つから一つ選択するようになっている。
例えば Blackにチェックがついている状態でCheckboardを選ぶと、Balckのチェックが外れ Checkboardにチェックが付く。これを実装するには少し工夫が必要で以前はTarget/Actionを使って力技で対処した。
Cocoaの日々: simpleCapへコンテキストメニューを追加 (2)
今回はTarget/Actionではなく Cocoa Bindings で対処してみた。
NSMenuItemの Value へモデルを紐付け(バインディイング)しておくと、その値に応じてメニューにチェックが付いたり、外れたりする。例えば下の図では NSMenuItem "Balck" に backgroundBlack というモデルを紐づけてある。モデルのオーナーは "Simple Viewer Controller" にした。これは InterfaceBuilder上でインスタンス化してあって扱いやすいため。同様に "Checkboard"には backgroundCheckboard、"White"には backgroundWhite という名前を紐づけておく。
次はモデルの実装を行う。Cocoa Bindings では Key-Value-Codingの仕組みを採用しているので実体はなんであれ setter/getter を用意してやるとそれが使われる。先ほどの backgroundBlack というモデルの場合、下記のようなインターフェイスを用意すればいい。
- (BOOL)backgroundBlack;
- (void)setBackgroundBlack:(BOOL)flag;
同様に他のモデルも用意してやる。
- (BOOL)backgroundWhite;
- (void)setBackgroundWhite:(BOOL)flag;
- (BOOL)backgroundCheckboard;
- (void)setBackgroundCheckboard:(BOOL)flag;
これでメニューが表示される時、もしくは選択された場合は自動的にこれらのメソッドが呼出される。
さて実装だが、背景の値はUserDefaultsで管理している。この実体は整数値で 0=Black, 1=Checkboard, 2=Whiteと割当てある。
それを踏まえた上で backgroundBlackの実装を見てみよう。まずメニューを表示する時には現在の値をチェックする為に getter である #backgroundBlack が呼出される。チェックを付けるか否かは背景値が 0(=Black)かどうかで判断できる。こんな感じ。
- (BOOL)backgroundBlack{
return ([[UserDefaults valueForKey:UDKEY_VIEWER_BACKGROUND] intValue] == 0);
}
次はメニューで選択された時。この場合は setterにあたる #setBackgroundBlack: が呼ばれる。
- (void)setBackgroundBlack:(BOOL)flag
{
if (flag) {
[UserDefaults setValue:[NSNumber numberWithInt:0] forKey:UDKEY_VIEWER_BACKGROUND];
[self setBackgroundCheckboard:NO];
[self setBackgroundWhite:NO];
[UserDefaults save];
} else if ([[UserDefaults valueForKey:UDKEY_VIEWER_BACKGROUND] intValue] == 0) {
[self setBackgroundCheckboard:YES];
}
}
もし flag==YES ならチェックされたことになるので、他の checkboard, white の値を NOにする。これが排他処理のポイント。そして後半の else if は、元々チェックが付いている状態で選択がされた時の処理を行っている。何もしないと見た目はチェックが外れてしまうので、今回は次の checkboardにチェックが付く様にしておいた。blackからチェックを外さないというインターフェイスもあるが、今回のBindingsだけを使う方法では難しい。特に害は無いと思うので今回はこれで行こう。
他の2つの設定についても同じ処理を書けばできあがり。
- - - -
もっとスマートな方法があると良いのだが
今はこれが精一杯か。
(良い方法があれば是非教えて欲しい)
2009年2月10日火曜日
SimpleViewer - コンテキストメニュー
SimpleViewerにコンテキストメニューをつける。
枠線の表示や背景の切り替えはプレファレンスで行っていたが、これらは画像を見ながら切り替えができた方がいい。ついでに直前の方法によるキャプチャと(ペーストボードへの)コピーも入れてみよう。
投稿者 xcatsan 時刻: 6:10
ラベル: cocoa, SimpleViewer
2009年2月9日月曜日
2009年2月8日日曜日
デスクトップアイコンを消す(その1)Selection編
シェアウェアにデスクトップアイコンを一時的に消すソフトがあるらしい。面白い。SimpleCapでもこれをやってみよう。
まずは Selectionから。
プリファレンスで制御できるようにする。
実際にキャプチャしてみよう。まずは通常のキャプチャ。デスクトップアイコンが写っている。
プリファレンスで "Exclude Desktop Icons"を選びキャプチャ。アイコンがそっくり消えている。
- - - -
デスクトップアイコンを消すのは簡単で CGWindowListCreateImage( )関数の CGWindowImageOption引数へ kCGWindowListExcludeDesktopElements を加えれば良い。ただこのオプションは背景画像まで取り除いてしまう。
そこでこのオプションを使ってキャプチャした後、背景画像を合成してやる。デスクトップ画像は以前マルチスクリーン対応で用意した DesktopWindowクラスを使うと比較的容易に作れる。
NSArray* desktop_window_list = [[DesktopWindow sharedDesktopWindow] CGWindowIDlist];
CGWindowID *windowIDs = calloc([desktop_window_list count], sizeof(CGWindowID));
int widx = 0;
for (NSNumber* num in desktop_window_list) {
windowIDs[widx++] = [num unsignedIntValue];
}
CFArrayRef windowIDsArray = CFArrayCreate(kCFAllocatorDefault, (const void**)windowIDs, widx, NULL);
CGImageRef cgimage_desktop = CGWindowListCreateImageFromArray(NSRectToCGRect(_rect), windowIDsArray, kCGWindowImageDefault);
これを別途キャプチャした画像と合成すれば良い。 こんな感じ。
NSBitmapImageRep *bitmap_desktop = [[[NSBitmapImageRep alloc] initWithCGImage:cgimage_desktop] autorelease];
NSImage* image_desktop = [[[NSImage alloc] init] autorelease];
[image_desktop addRepresentation:bitmap_desktop];
[image_desktop lockFocus];
[src_image drawAtPoint:NSZeroPoint
fromRect:NSZeroRect
operation:NSCompositeSourceOver fraction:1.0];
[image_desktop unlockFocus];
src_image = image_desktop;