スクリーントップの1ラインをminu切り替えのスイッチにする
メニューバー右側のアイコンメニューをなるべく多く表示することを目的としたアプリケーションminuをアクティブにするには、現状はコマンド + タブやDockでアプリケーション切り替えするしかない。これを改善して、メニューバーの一番上の1水平ラインをクリックすることで、minuに切り替えられるようにしようと思う。大まかな処理の流れは以下のような感じ。
- メニューバーよりも上に重なる透明ウィンドウを用意する。
- 上記ウィンドウに水平ラインを一本引く。
- マウスイベントを処理する。
早速、作業開始!
透明ウィンドウを作る
透明ウィンドウは背景がガラスのように透明で、文字や図形が描画された部分以外は、その下の情報がすべて透き通って見える。感覚的にはデスクトップ上で、まるでフォトショップのレイヤーを手に入れたような操作が可能で、とても応用力のある技だと思う。以下のURLにアップルのサンプルコードが置かれている。
そして、上記サンプルコードを日本語で、これ以上無いというほど親切丁寧に解説してくれているのが、Cocoaはやっぱりの以下のページ。
上記サンプルコードと解説を参考にすると、まず必要になるのが透明ウィンドウを定義するためのNSWindowのサブクラス。ClearWindowとして以下のように定義してみた。
// ---------- ファイル名: CrearWindow.h ---------- #import <Cocoa/Cocoa.h> @interface ClearWindow : NSWindow { } @end
// ---------- ファイル名: CrearWindow.m ---------- #import "ClearWindow.h" @implementation ClearWindow static float MENU_BAR_HEIGHT = 22; // ウィンドウを初期化して生成 - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag { NSRect mainScreenFrame = [[NSScreen mainScreen] frame]; NSRect areaFrame = NSMakeRect(mainScreenFrame.origin.x, mainScreenFrame.size.height - MENU_BAR_HEIGHT, mainScreenFrame.size.width, MENU_BAR_HEIGHT); //ウィンドウの初期化(NSBorderlessWindowMaskによってメニューバーを超えた移動が可能になる) id win = [super initWithContentRect:areaFrame styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag]; //ウィンドウが描画される上下レベル(レイヤーレベル)を設定(メニューバーよりも上のレベルに) [win setLevel: NSPopUpMenuWindowLevel]; //ウィンドウの背景色を透明色に設定 [win setBackgroundColor: [NSColor clearColor]]; //ウィンドウは不透明でない(つまり、透明である) [win setOpaque:NO]; //ウィンドウの透過率を設定(不透明1.0〜完全透明0.0) [win setAlphaValue:0.0]; //ウィンドウの影を表示しない [win setHasShadow: NO]; //ウィンドウをすべてのSpaceで表示する(Spaces対応のため) [win setCanBeVisibleOnAllSpaces: YES]; return win; } @end
- ウィンドウの背景色を透明にしたら([win setBackgroundColor: [NSColor clearColor]];)、ウィンドウの不透明さも常にNOにしておくべき([win setOpaque:NO];)。それにしても、なぜ不透明さの設定項目があるのか...。
- 上記二つの設定とは無関係に、ウィンドウの透過率を設定することができる([win setAlphaValue:0.0];)。1から0の範囲で、1は全く透過しない不透明、0だと完全に透明で見えなくなる。
イベント処理をする水平ラインを作る
- 今のところ、水平ラインをクリックしたらminuをアクティブにするだけなので、特別なイベント処理は必要ないが、この後の発展を考えてNSViewのサブクラスを作っておいた。
- 水平ラインの色には、GUI部品にキーボードでアクセスする時のフォーカスリングの色を指定した。([[NSColor keyboardFocusIndicatorColor] set];//自分の環境では青っぽい水色になる。)
// ---------- ファイル名: EventView.h ---------- #import <Cocoa/Cocoa.h> @interface EventView : NSView { } @end
// ---------- ファイル名: EventView.m ---------- #import "EventView.h" @implementation EventView - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code here. } return self; } - (void)drawRect:(NSRect)rect { //一番上に水平ラインを描画 NSRect aFrame = [self frame]; NSPoint point0 = NSMakePoint(aFrame.origin.x, NSHeight(aFrame)); NSPoint point1 = NSMakePoint(NSWidth(aFrame), NSHeight(aFrame)); [[NSColor keyboardFocusIndicatorColor] set]; [NSBezierPath setDefaultLineWidth:2]; [NSBezierPath strokeLineFromPoint:point0 toPoint:point1]; } @end
設計したクラスをInterface Builderから利用する
ClearWindowの設定
EventViewの設定
- MainMenu.nilウィンドウのWindowアイコンをダブルクリックして、(GUI設計用の)ウィンドウを開く。
- キーボードショットカット「コマンド + シフト + L」を実行して、ライブラリ ウィンドウを開く。
- 下の方の検索ボックスで「view」と入力してみる。
- 検索結果から「CustomView」を探して、(GUI設計用の)ウィンドウにドラッグ&ドロップ。
- 「Identify」インスペクタ ウィンドウの「Class」項目にXcodeで設計した「EventView」を選択。
- 「コマンド + 1」のキーボードショットカットを実行して、「size」インスペクタ ウィンドウを開く。
- 「EventView」の高さはメニューバーと同じ22を指定。
- 「EventView」を上に寄せて、横幅はウィンドウと同じ幅で配置した。
- 「EventView」のAutosizingで、上左右の位置固定、幅のみ伸縮自在の設定にしておく。
ここまで設定して、Interface Builderで一旦保存した。Xcodeに戻って、「ビルドして進行」を実行すると、スクリーントップに水色の水平ラインが引かれた!クリッックすれば、アプリケーションminuがアクティブになって、メニューバーのフリースペースを最大にしてくれる。
でも、文字メニューを操作したい時に間違ってクリックしてしまうと、不要なアプリケーションminuに切り替わってしまいガックリ...。今後の改善点はこの辺になりそうだ。