1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#import "SkOptionsTableView.h"
10#import "SkTextFieldCell.h"
11@implementation SkOptionItem
12@synthesize fCell, fItem;
13- (void)dealloc {
14    [fCell release];
15    [super dealloc];
16}
17@end
18
19@implementation SkOptionsTableView
20@synthesize fItems;
21
22- (id)initWithCoder:(NSCoder*)coder {
23    if ((self = [super initWithCoder:coder])) {
24        self.dataSource = self;
25        self.delegate = self;
26        fMenus = NULL;
27        fShowKeys = YES;
28        [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
29        self.fItems = [NSMutableArray array];
30    }
31    return self;
32}
33
34- (void)dealloc {
35    self.fItems = nil;
36    [super dealloc];
37}
38
39- (void) view:(SkNSView*)view didAddMenu:(const SkOSMenu*)menu {}
40- (void) view:(SkNSView*)view didUpdateMenu:(const SkOSMenu*)menu {
41    [self updateMenu:menu];
42}
43
44- (IBAction)toggleKeyEquivalents:(id)sender {
45    fShowKeys = !fShowKeys;
46    NSMenuItem* item = (NSMenuItem*)sender;
47    [item setState:fShowKeys];
48    [self reloadData];
49}
50
51- (void)registerMenus:(const SkTDArray<SkOSMenu*>*)menus {
52    fMenus = menus;
53    for (int i = 0; i < fMenus->count(); ++i) {
54        [self loadMenu:(*fMenus)[i]];
55    }
56}
57
58- (void)updateMenu:(const SkOSMenu*)menu {
59    // the first menu is always assumed to be the static, the second is
60    // repopulated every time over and over again
61
62    // seems pretty weird that we have to get rid of the const'ness here,
63    // but trying to propagate the const'ness through all the way to the fMenus
64    // vector was a non-starter.
65
66    int menuIndex = fMenus->find(const_cast<SkOSMenu *>(menu));
67    if (menuIndex >= 0 && menuIndex < fMenus->count()) {
68        NSUInteger first = 0;
69        for (int i = 0; i < menuIndex; ++i) {
70            first += (*fMenus)[i]->getCount();
71        }
72        [fItems removeObjectsInRange:NSMakeRange(first, [fItems count] - first)];
73        [self loadMenu:menu];
74    }
75    [self reloadData];
76}
77
78- (NSCellStateValue)triStateToNSState:(SkOSMenu::TriState)state {
79    if (SkOSMenu::kOnState == state)
80        return NSOnState;
81    else if (SkOSMenu::kOffState == state)
82        return NSOffState;
83    else
84        return NSMixedState;
85}
86
87- (void)loadMenu:(const SkOSMenu*)menu {
88    const SkOSMenu::Item* menuitems[menu->getCount()];
89    menu->getItems(menuitems);
90    for (int i = 0; i < menu->getCount(); ++i) {
91        const SkOSMenu::Item* item = menuitems[i];
92        SkOptionItem* option = [[SkOptionItem alloc] init];
93        option.fItem = item;
94
95        if (SkOSMenu::kList_Type == item->getType()) {
96            int index = 0, count = 0;
97            SkOSMenu::FindListItemCount(*item->getEvent(), &count);
98            NSMutableArray* optionstrs = [[NSMutableArray alloc] initWithCapacity:count];
99            SkAutoTDeleteArray<SkString> ada(new SkString[count]);
100            SkString* options = ada.get();
101            SkOSMenu::FindListItems(*item->getEvent(), options);
102            for (int i = 0; i < count; ++i)
103                [optionstrs addObject:[NSString stringWithUTF8String:options[i].c_str()]];
104            SkOSMenu::FindListIndex(*item->getEvent(), item->getSlotName(), &index);
105            option.fCell = [self createList:optionstrs current:index];
106            [optionstrs release];
107        }
108        else {
109            bool state = false;
110            SkString str;
111            SkOSMenu::TriState tristate;
112            switch (item->getType()) {
113                case SkOSMenu::kAction_Type:
114                    option.fCell = [self createAction];
115                    break;
116                case SkOSMenu::kSlider_Type:
117                    SkScalar min, max, value;
118                    SkOSMenu::FindSliderValue(*item->getEvent(), item->getSlotName(), &value);
119                    SkOSMenu::FindSliderMin(*item->getEvent(), &min);
120                    SkOSMenu::FindSliderMax(*item->getEvent(), &max);
121                    option.fCell = [self createSlider:value
122                                                  min:min
123                                                  max:max];
124                    break;
125                case SkOSMenu::kSwitch_Type:
126                    SkOSMenu::FindSwitchState(*item->getEvent(), item->getSlotName(), &state);
127                    option.fCell = [self createSwitch:(BOOL)state];
128                    break;
129                case SkOSMenu::kTriState_Type:
130                    SkOSMenu::FindTriState(*item->getEvent(), item->getSlotName(), &tristate);
131                    option.fCell = [self createTriState:[self triStateToNSState:tristate]];
132                    break;
133                case SkOSMenu::kTextField_Type:
134                    SkOSMenu::FindText(*item->getEvent(),item->getSlotName(), &str);
135                    option.fCell = [self createTextField:[NSString stringWithUTF8String:str.c_str()]];
136                    break;
137                default:
138                    break;
139            }
140        }
141        [fItems addObject:option];
142        [option release];
143    }
144}
145
146- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
147    return [self.fItems count];
148}
149
150- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
151    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
152    if (columnIndex == 0) {
153        const SkOSMenu::Item* item = ((SkOptionItem*)[fItems objectAtIndex:row]).fItem;
154        NSString* label = [NSString stringWithUTF8String:item->getLabel()];
155        if (fShowKeys)
156            return [NSString stringWithFormat:@"%@ (%c)", label, item->getKeyEquivalent()];
157        else
158            return label;
159    }
160    else
161        return nil;
162}
163
164- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
165    if (tableColumn) {
166        NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
167        if (columnIndex == 1)
168            return [((SkOptionItem*)[fItems objectAtIndex:row]).fCell copy];
169        else
170            return [[[SkTextFieldCell alloc] init] autorelease];
171    }
172    return nil;
173}
174
175- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
176    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
177    if (columnIndex == 1) {
178        SkOptionItem* option = (SkOptionItem*)[self.fItems objectAtIndex:row];
179        NSCell* storedCell = option.fCell;
180        const SkOSMenu::Item* item = option.fItem;
181        switch (item->getType()) {
182            case SkOSMenu::kAction_Type:
183                break;
184            case SkOSMenu::kList_Type:
185                [cell selectItemAtIndex:[(NSPopUpButtonCell*)storedCell indexOfSelectedItem]];
186                break;
187            case SkOSMenu::kSlider_Type:
188                [cell setFloatValue:[storedCell floatValue]];
189                break;
190            case SkOSMenu::kSwitch_Type:
191                [cell setState:[(NSButtonCell*)storedCell state]];
192                break;
193            case SkOSMenu::kTextField_Type:
194                if ([[storedCell stringValue] length] > 0)
195                    [cell setStringValue:[storedCell stringValue]];
196                break;
197            case SkOSMenu::kTriState_Type:
198                [cell setState:[(NSButtonCell*)storedCell state]];
199                break;
200            default:
201                break;
202        }
203    }
204    else {
205        [(SkTextFieldCell*)cell setEditable:NO];
206    }
207}
208
209- (void)tableView:(NSTableView *)tableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
210    NSInteger columnIndex = [tableView columnWithIdentifier:[tableColumn identifier]];
211    if (columnIndex == 1) {
212        SkOptionItem* option = (SkOptionItem*)[self.fItems objectAtIndex:row];
213        NSCell* cell = option.fCell;
214        const SkOSMenu::Item* item = option.fItem;
215        switch (item->getType()) {
216            case SkOSMenu::kAction_Type:
217                item->postEvent();
218                break;
219            case SkOSMenu::kList_Type:
220                [(NSPopUpButtonCell*)cell selectItemAtIndex:[anObject intValue]];
221                item->setInt([anObject intValue]);
222                break;
223            case SkOSMenu::kSlider_Type:
224                [cell setFloatValue:[anObject floatValue]];
225                item->setScalar([anObject floatValue]);
226                break;
227            case SkOSMenu::kSwitch_Type:
228                [cell setState:[anObject boolValue]];
229                item->setBool([anObject boolValue]);
230                break;
231            case SkOSMenu::kTextField_Type:
232                if ([anObject length] > 0) {
233                    [cell setStringValue:anObject];
234                    item->setString([anObject UTF8String]);
235                }
236                break;
237            case SkOSMenu::kTriState_Type:
238                [cell setState:[anObject intValue]];
239                item->setTriState((SkOSMenu::TriState)[anObject intValue]);
240                break;
241            default:
242                break;
243        }
244        item->postEvent();
245    }
246}
247
248- (NSCell*)createAction{
249    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
250    [cell setTitle:@""];
251    [cell setButtonType:NSMomentaryPushInButton];
252    [cell setBezelStyle:NSSmallSquareBezelStyle];
253    return cell;
254}
255
256- (NSCell*)createList:(NSArray*)items current:(int)index {
257    NSPopUpButtonCell* cell = [[[NSPopUpButtonCell alloc] init] autorelease];
258    [cell addItemsWithTitles:items];
259    [cell selectItemAtIndex:index];
260    [cell setArrowPosition:NSPopUpArrowAtBottom];
261    [cell setBezelStyle:NSSmallSquareBezelStyle];
262    return cell;
263}
264
265- (NSCell*)createSlider:(float)value min:(float)min max:(float)max {
266    NSSliderCell* cell = [[[NSSliderCell alloc] init] autorelease];
267    [cell setFloatValue:value];
268    [cell setMinValue:min];
269    [cell setMaxValue:max];
270    return cell;
271}
272
273- (NSCell*)createSwitch:(BOOL)state {
274    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
275    [cell setState:state];
276    [cell setTitle:@""];
277    [cell setButtonType:NSSwitchButton];
278    return cell;
279}
280
281- (NSCell*)createTextField:(NSString*)placeHolder {
282    SkTextFieldCell* cell = [[[SkTextFieldCell alloc] init] autorelease];
283    [cell setEditable:YES];
284    [cell setStringValue:@""];
285    [cell setPlaceholderString:placeHolder];
286    return cell;
287}
288
289- (NSCell*)createTriState:(NSCellStateValue)state {
290    NSButtonCell* cell = [[[NSButtonCell alloc] init] autorelease];
291    [cell setAllowsMixedState:TRUE];
292    [cell setTitle:@""];
293    [cell setState:(NSInteger)state];
294    [cell setButtonType:NSSwitchButton];
295    return cell;
296}
297@end
298