SHE (Selection History Expose) を試しに使っていてわかったのは、1度きりしか使わない範囲を表示すると画面が範囲だらけになって本来使いまわしたい範囲がわかりづらいこと。
使用回数を保持する
よく使う範囲と1回しか使わない範囲を区別する必要があるな。とりあえず使った回数を保持しておくことにする。SHEの履歴は SelectionHistoryクラスで管理している。
@interface SelectionHistory : NSObject { NSMutableArray* _historyArray; NSArray* _cachedArrayOrderBySize; NSArray* _cachedArrayOrderBySizeDesc; } + (SelectionHistory*)sharedSelectionHistory; - (void)addHistoryRect:(NSRect)frame; - (NSArray*)array; - (NSArray*)arrayOrderBySize; - (NSArray*)arrayOrderBySizeDesc; - (void)clearAll; @end配列 _historyArray には NSRect を NSValue でラップしていれていた。これをやめる。新たに SelectionHistoryEntryクラスを導入して、これで履歴1つ分の範囲矩形と使用回数を管理する。
@interface SelectionHistoryEntry : NSObject { NSRect _rect; NSInteger _count; } @property (nonatomic, assign) NSRect rect; @property (nonatomic, assign) NSInteger count; @end保存は以前と同様に NSUserDefaultsに行う。SelectionHistoryEntryのシリアライズが必要だが今回は安易に NSMutableDictionaryに @"count", @"rect" をキーにして値を入れてそれを保存した(NSMutableDictionaryは標準で NSUserDefaultsに保存できる)。
- (void)save { NSMutableArray* array = [NSMutableArray array]; for (SelectionHistoryEntry* entry in _historyArray) { NSMutableDictionary* dict = [NSMutableDictionary dictionary]; [dict setObject:NSStringFromRect(entry.rect) forKey:@"rect"]; [dict setObject:[NSNumber numberWithInteger:entry.count] forKey:@"count"]; [array addObject:dict]; } [UserDefaults setValue:array forKey:UDKEY_SELECTION_HISTORY]; [UserDefaults save]; }試しに実行して save時の履歴をログへ出してみよう。
SimpleCap[9099:a0f] SAVE: ( { count = 1; rect = "{{870, 135}, {254, 163}}"; }, { count = 3; rect = "{{208, 203}, {400, 250}}"; } )よさそうだ。
サイズの小さい順にソート
なお SelectionHistory クラスでは arrayOrderBySize というメソッドを用意していて、これを使うと履歴をサイズの小さい順で得ることができる。サイズの比較は今回は矩形の面積で判断するようにした。
NSInteger sizeSort(id obj1, id obj2, void* context) { NSRect rect1 = [obj1 rect]; NSRect rect2 = [obj2 rect]; CGFloat area1 = rect1.size.width * rect1.size.height; CGFloat area2 = rect2.size.width * rect2.size.height; if (area1 < area2) { return NSOrderedAscending; } else if (area1 > area2) { return NSOrderedDescending; } else { CGFloat len1 = rect1.origin.x*rect1.origin.x + rect1.origin.y*rect1.origin.y; CGFloat len2 = rect2.origin.x*rect2.origin.x + rect2.origin.y*rect2.origin.y; if (len1 < len2) { return NSOrderedAscending; } else if (len1 > len2) { return NSOrderedDescending; } else { return NSOrderedSame; } } }またソート結果はマウスオーバーの判断でよく使うのでキャッシュしてある。履歴の内容が変わらない限りはこのキャッシュを使う。
- (NSArray*)arrayOrderBySize { if (!_cachedArrayOrderBySize) { _cachedArrayOrderBySize = [[_historyArray sortedArrayUsingFunction:sizeSort context:NULL] retain]; } return _cachedArrayOrderBySize; }
- - - -
使用回数が取れるようになったので次回はこれを活用してみよう。
Responses
Leave a Response