さていよいよタイマーダイアログを SimpleCap へ組み込む。組み込み方は、CaptureControllerが TimerControllerのインスタンスを持ち、各種Handlerとの仲介を果たす。タイマーを使いたい Handlerは CaptureController#startTimerOnClinet: を呼出す。すると 
まずはスクリーンキャプチャへ組み込んでみた。
部品化(クラス化)ができているので少しの変更で動作した。
2008年7月4日金曜日
SimpleCap(11)- タイマーダイアログ組み込み
2008年7月3日木曜日
2008年7月2日水曜日
タイマーダイアログ(その9)
カウントの増加が1秒単位だけだと1分など長い時間に設定したい時に使いづらい。ボタンを増やしたくないので Shiftキーを押した時には 10秒単位の増減にしよう。
Shiftキーが押されたかどうかは NSEvent#modifierFlags が利用できる。ボタンが押された時にこの値と NSSfhitKeyMask で論理積(AND)をとってやる。
Shiftキーの有無によってカウントの増減量 dc の設定を変えている。
ThimerControllerm.m
-(void)clickedAtTag:(NSNumber*)tag event:(NSEvent*)event
{
BOOL is_shiftkey = ([event modifierFlags] & NSShiftKeyMask) ? YES : NO;
int dc = 1;
if (is_shiftkey) {
dc = 10;
}
:
元々 ThinButtonBar からのコールバックには NSEventは含まれていなかったので今回これも追加した。
[_delegate performSelector:@selector(clickedAtTag:event:)
withObject:[NSNumber numberWithInt:[hitButton tag]]
withObject:theEvent];
幸いなことに performSelector: には引数2個まで対応しているので簡単にできた。
NSObject.h
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
調子に乗って1000秒まで増やしてみた(それだけ)。
2008年7月1日火曜日
タイマーダイアログ(その8)
2008年6月30日月曜日
タイマーダイアログ(その7)
次はタイマーの値を増減できるようにする。左下に「+」と「ー」のボタンを追加した。
このボタンを押した場合に次のような意味も持たせる。
・一時停止する
・初期値(サンプルでは10秒)も合わせて変更する
「自明な表示や操作は省き、経験則に従った最小限の操作で目的が達成できる」というのがユーザインターフェイスを作る上での私のポリシーなので、それ合わせて上記のようにしてみた。ただユーザインターフェイスは実際に使わないと分からないので、この辺りは何度か試行錯誤しながらブラッシュアップしていく。
ボタンの追加はPNG画像を用意しておなじみの(?)ThinButtonBar クラスを使う。影を付けたくなかったのでその拡張を加えてある。
サンプル:TimerDialog-05.zip
2008年6月29日日曜日
タイマーダイアログ(その6)
タイマー開始ボタンを押したら、一時停止ボタンへ差し替える処理を加える。
最初は開始ボタンで、
開始後、一時停止ボタンになる。
ソース:TimerDialog-04.zip
今回の動作を行わせる為に、ThinButtonBar へグループという概念を追加した。
まずボタンを作る際にグループ(文字列)を指定するようにした。
[_button_bar addButtonWithImageResource:@"icon_cancel"
alterImageResource:@"icon_cancel2"
tag:TAG_CANCEL_TIMER
tooltip:NSLocalizedString(@"CancelTimer", @"")
group:nil];
[_button_bar addButtonWithImageResource:@"icon_start_timer"
alterImageResource:@"icon_start_timer2"
tag:TAG_START_TIMER
tooltip:NSLocalizedString(@"StartTimer", @"")
group:@"START_PAUSE"];
[_button_bar addButtonWithImageResource:@"icon_pause_timer"
alterImageResource:@"icon_pause_timer2"
tag:TAG_PAUSE_TIMER
tooltip:NSLocalizedString(@"PauseTimer", @"")
group:@"START_PAUSE"];
上記では2番目(開始ボタン)と3番目(一時停止ボタン)が同じ "START_PAUSE"グループに所属する。
ThinButtonBar にグループを管理する _group_list を追加した。これを使い、ボタン登録時に同じグループのボタンが存在する場合は従来の管理リスト _list へは追加せず、_group_list へ追加するようにした。ボタンの描画やヒットテストは _list を対象としているので特に修正はいらない。
ボタンが押された場合、そのボタンがグループに所属する場合にはグループ内の次の順番のボタンに _listを置き換える。これで開始ボタンを押した後に一時停止ボタンに表示が変わる。
ThinButton.m
:
NSArray* group_array = [_group_list objectForKey:[hitButton group]];
if (group_array) {
NSUInteger i = 0;
ThinButton* button;
for (button in group_array) {
i++;
if (button == hitButton) {
break;
}
}
if (i == [group_array count]) {
i = 0;
}
button = [group_array objectAtIndex:i];
[self exchangeButtonFrom:hitButton To:button];
}
:
タイマー完了後は元の開始ボタンに表示を変える為に #resetGroup を呼出している。このメソッドはグループ内の0番目のボタンへ戻す処理を行う。
- (void)resetGroup:(NSString*)group
{
NSArray* group_array = [_group_list objectForKey:group];
if (group_array && [group_array count] > 0) {
ThinButton *new = [group_array objectAtIndex:0];
for (ThinButton *old in _list) {
if ([group isEqualToString:[old group]]) {
[self exchangeButtonFrom:old To:new];
}
}
}
}
2008年6月26日木曜日
タイマーダイアログ(その5)
数字でカウントダウンを表示してみる。TimerView からTimerController を参照するようにし、1秒毎に再描画させる。
描画コード。
TimerWindowView.m
- (void)drawRect:(NSRect)rect
{
:
:
int count = [_controller lastCount];
NSPoint p;
NSMutableAttributedString* str =
[[NSMutableAttributedString alloc]
initWithString:[NSString stringWithFormat:@"%d", count]];
[str addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Arial" size:72]
range:NSMakeRange(0, 1)];
[str addAttribute:NSForegroundColorAttributeName value:[NSColor whiteColor]
range:NSMakeRange(0, 1)];
NSSize str_size = [str size];
p.x = (wb.size.width - str_size.width) /2;
p.y = (wb.size.height - str_size.height) /2 - COUNT_STR_OFFSET;
[[NSColor whiteColor] set];
[NSGraphicsContext saveGraphicsState];
[_shadow set];
[str drawAtPoint:p];
[NSGraphicsContext restoreGraphicsState];
Arialフォント 72pt で数字を描く。描画位置はウィンドウの(おおまか)中心にくるように計算してある。
するとこんな感じになる。

- - - -
まずは最低限のものができた。次は現在別々になっている開始・一時停止ボタンをまとめてみよう。
2008年6月25日水曜日
タイマーダイアログ(その4)
アイコンを作図し、以前開発したThinButtonBarクラスを使ってボタン表示した。
TimerController に表示のコントロールもまかせる。
TimerController.m
- (id)init
{
self = [super init];
if (self) {
_interval = 1.0;
_times = 0;
_timer = nil;
[self reset];
_window = [[TimerWindow alloc] init];
_view = [[TimerWindowView alloc] initWithFrame:[_window frame]];
[_window setContentView:_view];
[_window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
[_window makeKeyAndOrderFront:self];
_button_bar = [[ThinButtonBar alloc] initWithFrame:NSZeroRect];
[_button_bar addButtonWithImageResource:@"icon_start_timer"
alterImageResource:@"icon_start_timer2"
tag:TAG_START_TIMER
tooltip:NSLocalizedString(@"StartTimer", @"")];
[_button_bar addButtonWithImageResource:@"icon_pause_timer"
alterImageResource:@"icon_pause_timer2"
tag:TAG_PAUSE_TIMER
tooltip:NSLocalizedString(@"PauseTimer", @"")];
[_button_bar addButtonWithImageResource:@"icon_cancel"
alterImageResource:@"icon_cancel2"
tag:TAG_CANCEL_TIMER
tooltip:NSLocalizedString(@"CancelTimer", @"")];
[_view addSubview:_button_bar];
[_button_bar setDelegate:self];
[_button_bar setPosition:SC_BUTTON_POSITION_CENTER];
[_button_bar setButtonBarWithFrame:[_view frame]];
[_button_bar show];
}
return self;
}
ソース:TimerDialog-03.zip
- - - -
後はカウント値の表示か。
2008年6月24日火曜日
タイマーダイアログ(その3)
機能の実装から入る。インターフェイスは次のようにしよう。
TimerControllerは「停止」「実行中」「一時停止」に3種類の状態を持つ。状態遷移と各メソッドは次のように対応づけられる。
ソースは取り立てて難しいことはやっていないので割愛する。
動作確認の為に簡単な GUIを付けてみた。
よさそうだ。
ソース:TimerDialog-02.zip
- - - -
機能の実装ができた。後はこれを同表現するかだ。次回からデザインを入れていく。
2008年6月23日月曜日
2008年6月22日日曜日
タイマーダイアログ(その1)
SimpleCap ではタイマーが重要な役割を果たす。範囲選択やスクリーン全体、メニューキャプチャ、そして今後予定しているアプリケーションキャプチャなど様々な場面でタイマーを利用する。今まではカウントダウンなどの視覚効果をきちんと実装してこなかった。各機能の実装が進んできたのでここらで共通に使えるタイマーのユーザインターフェイスを用意する事にする。これを「タイマーダイアログ」と呼ぶことにする。イメージとしてはダイアログの形態を取り、カウントダウン表示のほか、一時停止や秒数調整など簡単な操作が行えるようなものを考えている。表示は HUDのような半透明を考えている。ただしこれまで SimpleCapは白を基調としてきたのでこれを踏襲する。
今回はまず手始めにカスタムウィンドウ(ダイアログ)を作る。
カスタムの NSWindow と NSView を用意する。
TimerWindow.m
- (id)init
{
NSRect rect = NSMakeRect(100, 100, 400, 250);
self = [super initWithContentRect:rect
styleMask:NSTexturedBackgroundWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if (self) {
[self setReleasedWhenClosed:YES];
[self setDisplaysWhenScreenProfileChanges:YES];
[self setBackgroundColor:[NSColor clearColor]];
[self setOpaque:NO];
[self setHasShadow:NO];
[self setIgnoresMouseEvents:NO];
}
return self;
}
NSTexturedBackgroundWindowMask を使うとウィンドウのどの部分でもドラッグして移動できるようになる。
まずは黒地と白枠を描く。
TimerWindowView.m
- (void)drawRect:(NSRect)rect {
// Drawing code here.
[[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.3] set];
NSRectFill(rect);
[[NSColor whiteColor] set];
NSFrameRectWithWidth(rect, 5);
[[NSColor lightGrayColor] set];
NSFrameRectWithWidth(rect, 0.5);
}これらを AppController で生成し紐づける。
AppController.m
- (void)awakeFromNib
{
_window = [[TimerWindow alloc] init];
_view = [[TimerWindowView alloc] initWithFrame:[_window frame]];
[_window setContentView:_view];
[_window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
[_window makeKeyAndOrderFront:self];
}
さて実行してみる。ドラッグして移動もできる。いい感じだ。

ソース:TimerDialog-01.zip
- - - -
次回は枠を丸く(RoundRect)にしてみる。





