iOS Sample App menu implementation
http://codereview.appspot.com/4798055/


git-svn-id: http://skia.googlecode.com/svn/trunk@2022 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/iOSSampleApp/Shared/SkOptionListController.h b/experimental/iOSSampleApp/Shared/SkOptionListController.h
new file mode 100644
index 0000000..480579a
--- /dev/null
+++ b/experimental/iOSSampleApp/Shared/SkOptionListController.h
@@ -0,0 +1,16 @@
+#import <UIKit/UIKit.h>
+
+@interface SkOptionListController : UITableViewController {    
+    NSMutableArray* fOptions;
+    NSInteger fSelectedIndex;
+    UITableViewCell* fSelectedCell;
+    UITableViewCell* fParentCell;
+}
+@property (nonatomic, retain) NSMutableArray* fOptions;
+@property (nonatomic, assign) NSInteger fSelectedIndex;
+@property (nonatomic, retain) UITableViewCell* fSelectedCell;
+@property (nonatomic, retain) UITableViewCell* fParentCell;
+
+- (void)addOption:(NSString*)option;
+- (NSString*)getSelectedOption;
+@end
diff --git a/experimental/iOSSampleApp/Shared/SkOptionListController.mm b/experimental/iOSSampleApp/Shared/SkOptionListController.mm
new file mode 100644
index 0000000..d524134
--- /dev/null
+++ b/experimental/iOSSampleApp/Shared/SkOptionListController.mm
@@ -0,0 +1,78 @@
+#import "SkOptionListController.h"
+
+@implementation SkOptionListController
+
+@synthesize fOptions, fSelectedIndex, fSelectedCell, fParentCell;
+
+#pragma mark -
+#pragma mark Initialization
+
+- (id)initWithStyle:(UITableViewStyle)style {
+    self = [super initWithStyle:style];
+    if (self) {
+        self.fOptions = [[NSMutableArray alloc] init];
+        self.fSelectedIndex = 0;
+        self.fSelectedCell = nil;
+    }
+    return self;
+}
+
+- (void)addOption:(NSString*)option {
+    [fOptions addObject:option];
+}
+
+- (NSString*)getSelectedOption {
+    return (NSString*)[fOptions objectAtIndex:self.fSelectedIndex];
+}
+
+#pragma mark -
+#pragma mark Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return [fOptions count];
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    
+    static NSString *CellIdentifier = @"Cell";
+    
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+    if (cell == nil) {
+        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+    }
+    
+    cell.textLabel.text = [fOptions objectAtIndex:indexPath.row];
+    if (indexPath.row == fSelectedIndex) {
+        cell.accessoryType = UITableViewCellAccessoryCheckmark;
+        self.fSelectedCell = cell;
+    }
+    else
+        cell.accessoryType = UITableViewCellAccessoryNone;
+    
+    return cell;
+}
+
+#pragma mark -
+#pragma mark Table view delegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
+    self.fSelectedCell.accessoryType = UITableViewCellAccessoryNone;
+    self.fSelectedCell = cell;
+    cell.accessoryType = UITableViewCellAccessoryCheckmark;
+    self.fParentCell.detailTextLabel.text = cell.textLabel.text;;
+    self.fSelectedIndex = indexPath.row;
+    [self.navigationController popViewControllerAnimated:YES];
+}
+
+- (void)dealloc {
+    self.fOptions = nil;
+    self.fSelectedCell = nil;
+    [super dealloc];
+}
+
+@end
diff --git a/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.h b/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.h
new file mode 100644
index 0000000..9c715aa
--- /dev/null
+++ b/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.h
@@ -0,0 +1,42 @@
+#import <UIKit/UIKit.h>
+#import "SkOptionListController.h"
+#import "SkOSMenu.h"
+#import "SkEvent.h"
+#import "SkUIView.h"
+@interface SkOptionItem : NSObject {
+    UITableViewCell* fCell;
+    const SkOSMenu::Item* fItem;
+}
+@property (nonatomic, assign) const SkOSMenu::Item* fItem;
+@property (nonatomic, retain) UITableViewCell* fCell;
+
+@end
+
+@interface SkOptionListItem : SkOptionItem{
+    SkOptionListController* fOptions;
+}
+@property (nonatomic, retain) SkOptionListController* fOptions;
+
+@end
+
+@interface SkOptionsTableViewController : UITableViewController <UINavigationControllerDelegate, SkUIViewOptionsDelegate> {
+    NSMutableArray* fItems;
+    const SkTDArray<SkOSMenu*>* fMenus;
+    SkOptionListItem* fCurrentList;
+}
+
+@property (nonatomic, retain) NSMutableArray* fItems;
+@property (nonatomic, retain) SkOptionListItem* fCurrentList;
+
+- (void)registerMenus:(const SkTDArray<SkOSMenu*>*)menus;
+- (void)updateMenu:(const SkOSMenu*)menu;
+- (void)loadMenu:(const SkOSMenu*)menu;
+
+- (UITableViewCell*)createAction:(NSString*)title;
+- (UITableViewCell*)createSlider:(NSString*)title min:(float)min max:(float)max default:(float)value;
+- (UITableViewCell*)createSwitch:(NSString*)title default:(BOOL)state;
+- (UITableViewCell*)createTriState:(NSString*)title default:(int)index;
+- (UITableViewCell*)createTextField:(NSString*)title default:(const char*)value;
+- (UITableViewCell*)createList:(NSString*)title default:(NSString*)value;
+
+@end
diff --git a/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.mm b/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.mm
new file mode 100644
index 0000000..46a7b29
--- /dev/null
+++ b/experimental/iOSSampleApp/Shared/SkOptionsTableViewController.mm
@@ -0,0 +1,325 @@
+#import "SkOptionsTableViewController.h"
+#include "SkEvent.h"
+
+@implementation SkOptionItem
+@synthesize fCell, fItem;
+- (void)dealloc {
+    [fCell release];
+    [super dealloc];
+}
+@end
+
+@implementation SkOptionListItem
+@synthesize fOptions;
+- (void)dealloc {
+    [fOptions release];
+    [super dealloc];
+}
+@end
+
+@implementation SkOptionsTableViewController
+
+@synthesize fItems, fCurrentList;
+
+- (id)initWithStyle:(UITableViewStyle)style {
+    self = [super initWithStyle:style];
+    if (self) {
+        self.fItems = [NSMutableArray array];
+    }
+    return self;
+}
+
+//SkUIViewOptionsDelegate
+- (void) view:(SkUIView*)view didAddMenu:(const SkOSMenu*)menu {}
+- (void) view:(SkUIView*)view didUpdateMenu:(const SkOSMenu*)menu {
+    [self updateMenu:menu];
+}
+
+- (NSUInteger)convertPathToIndex:(NSIndexPath*)path {
+    NSUInteger index = 0;
+    for (NSInteger i = 0; i < path.section; ++i) {
+        index += (*fMenus)[i]->countItems();
+    }
+    return index + path.row;
+}
+
+- (void)registerMenus:(const SkTDArray<SkOSMenu*>*)menus {
+    fMenus = menus;
+    for (NSUInteger i = 0; i < fMenus->count(); ++i) {
+        [self loadMenu:(*fMenus)[i]];
+    }
+}
+
+- (void)updateMenu:(SkOSMenu*)menu {
+    // the first menu is always assumed to be the static, the second is 
+    // repopulated every time over and over again 
+    int menuIndex = fMenus->find(menu);
+    if (menuIndex >= 0 && menuIndex < fMenus->count()) {
+        NSUInteger first = 0;
+        for (NSInteger i = 0; i < menuIndex; ++i) {
+            first += (*fMenus)[i]->countItems();
+        }
+        [fItems removeObjectsInRange:NSMakeRange(first, [fItems count] - first)];
+        [self loadMenu:menu];
+    }
+    [self.tableView reloadData];
+}
+
+- (void)loadMenu:(const SkOSMenu*)menu {
+    for (int i = 0; i < menu->countItems(); ++i) {
+        const SkOSMenu::Item* item = menu->getItem(i);
+        NSString* title = [NSString stringWithUTF8String:item->getLabel()];
+        
+        int index = 0;
+        NSArray* optionstrs = nil;
+        if (SkOSMenu::kList_Type == item->getType()) {
+            SkOptionListItem* List = [[SkOptionListItem alloc] init];
+            //List.fCmdID = item->fOSCmd;
+            //List.getEvent() = item->getEvent();
+            List.fItem = item;
+            List.fOptions = [[SkOptionListController alloc] initWithStyle:UITableViewStyleGrouped];
+            
+            NSArray* optionstrs = [[NSString stringWithUTF8String:item->getEvent()->findString(SkOSMenu::List_Items_Str)]
+                                   componentsSeparatedByString:[NSString stringWithUTF8String:SkOSMenu::Delimiter]];
+            for (NSString* optionstr in optionstrs) {
+                [List.fOptions addOption:optionstr];
+            }
+            item->getEvent()->findS32(item->getSlotName(), &index);
+            List.fOptions.fSelectedIndex = index;
+            List.fCell = [self createList:title
+                                      default:[List.fOptions getSelectedOption]];
+            List.fOptions.fParentCell = List.fCell;
+            [fItems addObject:List];
+            [List release];
+        }
+        else {
+            SkOptionItem* option = [[SkOptionItem alloc] init];
+            option.fItem = item;
+            bool state = false;
+            switch (item->getType()) {
+                case SkOSMenu::kAction_Type:
+                    option.fCell = [self createAction:title];
+                    break;
+                case SkOSMenu::kSwitch_Type:
+                    item->getEvent()->findBool(item->getSlotName(), &state);
+                    option.fCell = [self createSwitch:title default:(BOOL)state];
+                    break;
+                case SkOSMenu::kSlider_Type:
+                    SkScalar min, max, value;
+                    item->getEvent()->findScalar(SkOSMenu::Slider_Min_Scalar, &min);
+                    item->getEvent()->findScalar(SkOSMenu::Slider_Max_Scalar, &max);
+                    item->getEvent()->findScalar(item->getSlotName(), &value);
+                    option.fCell = [self createSlider:title 
+                                                  min:min 
+                                                  max:max
+                                              default:value];
+                    break;                    
+                case SkOSMenu::kTriState_Type:
+                    item->getEvent()->findS32(item->getSlotName(), &index);
+                    option.fCell = [self createTriState:title default:index];
+                    break;
+                case SkOSMenu::kTextField_Type:
+                    option.fCell = [self createTextField:title 
+                                                 default:item->getEvent()->findString(item->getSlotName())];
+                    break;
+                default:
+                    break;
+            }
+            [fItems addObject:option];
+            [option release];
+        }
+    }
+}
+
+- (void)valueChanged:(id)sender {
+    UITableViewCell* cell = (UITableViewCell*)(((UIView*)sender).superview);
+    NSUInteger index = [self convertPathToIndex:[self.tableView indexPathForCell:cell]];
+    SkOptionItem* item = (SkOptionItem*)[fItems objectAtIndex:index];
+    if ([sender isKindOfClass:[UISlider class]]) {//Slider
+        UISlider* slider = (UISlider *)sender;
+        cell.detailTextLabel.text = [NSString stringWithFormat:@"%1.1f", slider.value];
+        item.fItem->postEventWithScalar(slider.value);
+    }
+    else if ([sender isKindOfClass:[UISwitch class]]) {//Switch
+        UISwitch* switch_ = (UISwitch *)sender;
+        item.fItem->postEventWithBool(switch_.on);
+    }
+    else if ([sender isKindOfClass:[UITextField class]]) { //TextField
+        UITextField* textField = (UITextField *)sender;
+        [textField resignFirstResponder];
+        item.fItem->postEventWithString([textField.text UTF8String]);
+    }
+    else if ([sender isKindOfClass:[UISegmentedControl class]]) { //Action
+        UISegmentedControl* segmented = (UISegmentedControl *)sender;
+        item.fItem->postEventWithInt((2 == segmented.selectedSegmentIndex) ? 
+                                     SkOSMenu::kMixedState : 
+                                     segmented.selectedSegmentIndex);
+    }
+    else{
+        NSLog(@"unknown");
+    }
+}
+
+- (UITableViewCell*)createAction:(NSString*)title {
+    UITableViewCell* cell = [[[UITableViewCell alloc]
+                              initWithStyle:UITableViewCellStyleValue1 
+                              reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    return cell;
+}
+
+- (UITableViewCell*)createSwitch:(NSString*)title default:(BOOL)state {
+    UITableViewCell* cell = [[[UITableViewCell alloc] 
+                              initWithStyle:UITableViewCellStyleValue1 
+                              reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    UISwitch* switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
+    [switchView setOn:state animated:NO];
+    [switchView addTarget:self 
+                   action:@selector(valueChanged:) 
+         forControlEvents:UIControlEventValueChanged];
+    cell.accessoryView = switchView;
+    [switchView release];
+    return cell;
+}
+
+- (UITableViewCell*)createSlider:(NSString*)title 
+                             min:(float)min 
+                             max:(float)max 
+                         default:(float)value {
+    UITableViewCell* cell = [[[UITableViewCell alloc] 
+                             initWithStyle:UITableViewCellStyleValue1 
+                             reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    UISlider* sliderView = [[UISlider alloc] init];
+    sliderView.value = value;
+    sliderView.minimumValue = min;
+    sliderView.maximumValue = max;
+    [sliderView addTarget:self 
+                   action:@selector(valueChanged:) 
+         forControlEvents:UIControlEventValueChanged];
+    cell.detailTextLabel.text = [NSString stringWithFormat:@"%1.1f", value];
+    cell.accessoryView = sliderView; 
+    [sliderView release];
+    return cell;
+}
+
+- (UITableViewCell*)createTriState:(NSString*)title default:(int)index {
+    UITableViewCell* cell = [[[UITableViewCell alloc] 
+                              initWithStyle:UITableViewCellStyleValue1 
+                              reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    NSArray* items = [NSArray arrayWithObjects:@"Off", @"On", @"Mixed", nil];
+    UISegmentedControl* segmented = [[UISegmentedControl alloc] initWithItems:items];
+    segmented.selectedSegmentIndex = (index == -1) ? 2 : index;
+    segmented.segmentedControlStyle = UISegmentedControlStyleBar;
+    [segmented addTarget:self 
+                  action:@selector(valueChanged:) 
+        forControlEvents:UIControlEventValueChanged];
+    cell.accessoryView = segmented;
+    [segmented release];
+    return cell; 
+}
+
+- (UITableViewCell*)createTextField:(NSString*)title 
+                            default:(const char*)value {
+    UITableViewCell* cell = [[[UITableViewCell alloc] 
+                              initWithStyle:UITableViewCellStyleValue1 
+                              reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    UITextField* textField = [[UITextField alloc] 
+                              initWithFrame:CGRectMake(0, 10, 150, 25)];
+    textField.adjustsFontSizeToFitWidth = YES;
+    textField.textAlignment = UITextAlignmentRight;
+    textField.textColor = cell.detailTextLabel.textColor;
+    textField.placeholder = [NSString stringWithUTF8String:value];
+    textField.returnKeyType = UIReturnKeyDone;
+    [textField addTarget:self 
+                  action:@selector(valueChanged:) 
+        forControlEvents:UIControlEventEditingDidEndOnExit];
+    cell.accessoryView = textField; 
+    [textField release];
+    return cell;
+}
+
+- (UITableViewCell*)createList:(NSString*)title default:(NSString*)value{
+    UITableViewCell* cell = [[[UITableViewCell alloc] 
+                              initWithStyle:UITableViewCellStyleValue1 
+                              reuseIdentifier:nil] autorelease];
+    cell.textLabel.text = title;
+    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+    cell.detailTextLabel.text = value;
+    return cell; 
+}
+
+#pragma mark -
+#pragma mark Table view data source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+    return fMenus->count();
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+    return [NSString stringWithUTF8String:(*fMenus)[section]->getTitle()];
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return (*fMenus)[section]->countItems();
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    return ((SkOptionItem*)[fItems objectAtIndex:[self convertPathToIndex:indexPath]]).fCell;
+}
+
+#pragma mark -
+#pragma mark Table view delegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
+    id item = [fItems objectAtIndex:indexPath.row];
+    
+    if ([item isKindOfClass:[SkOptionListItem class]]) {
+        SkOptionListItem* list = (SkOptionListItem*)item;
+        self.fCurrentList = list;
+        self.navigationController.delegate = self;
+        [self.navigationController pushViewController:list.fOptions animated:YES];
+    }
+    else if ([item isKindOfClass:[SkOptionItem class]]) {
+        if (UITableViewCellSelectionStyleNone != cell.selectionStyle) { //Actions
+            SkOptionItem* action = (SkOptionItem*)item;
+            action.fItem->postEvent();
+        }
+    } 
+    else{
+        NSLog(@"unknown");
+    }
+
+    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
+}
+
+#pragma mark -
+#pragma mark Navigation controller delegate
+
+- (void)navigationController:(UINavigationController *)navigationController 
+      willShowViewController:(UIViewController *)viewController 
+                    animated:(BOOL)animated {
+    if (self == viewController) { //when a List option is popped, trigger event
+        NSString* selectedOption = [fCurrentList.fOptions getSelectedOption];
+        fCurrentList.fCell.detailTextLabel.text = selectedOption;
+        fCurrentList.fItem->postEventWithInt(fCurrentList.fOptions.fSelectedIndex);
+    }
+}
+
+#pragma mark -
+#pragma mark Memory management
+
+- (void)dealloc {
+    self.fItems = nil;
+    [super dealloc];
+}
+
+@end
\ No newline at end of file
diff --git a/experimental/iOSSampleApp/Shared/SkUIDetailViewController.h b/experimental/iOSSampleApp/Shared/SkUIDetailViewController.h
index 05d1f37..7435a9d 100644
--- a/experimental/iOSSampleApp/Shared/SkUIDetailViewController.h
+++ b/experimental/iOSSampleApp/Shared/SkUIDetailViewController.h
@@ -6,35 +6,34 @@
  * found in the LICENSE file.
  */
 #import <UIKit/UIKit.h>
+#import "SkOptionsTableViewController.h"
 #import "SkUIRootViewController.h"
 #import "SkUIView.h"
 
 class SampleWindow;
 class SkData;
 @interface SkUIDetailViewController : UIViewController {
-    UINavigationBar* fNavigationBar;
     UIPopoverController* fPopOverController;
+    SkOptionsTableViewController* fOptionsController;
     UIBarButtonItem* fPrintButton;
-    UIBarButtonItem* fCycleButton;
+    UIBarButtonItem* fOptionsButton;
     SkData* fData;
     SkUIView* fSkUIView;
     SampleWindow* fWind;
 }
-@property (nonatomic, retain) IBOutlet UINavigationBar *fNavigationBar;
+
 @property (nonatomic, retain) UIBarButtonItem* fPrintButton;
-@property (nonatomic, retain) UIBarButtonItem* fCycleButton;
+@property (nonatomic, retain) UIBarButtonItem* fOptionsButton;
+@property (nonatomic, retain) SkOptionsTableViewController* fOptionsController;
 @property (nonatomic, assign) UIPopoverController* fPopOverController;
 
 //Instance methods
-- (void)redraw;
 - (void)populateRoot:(SkUIRootViewController*)root;
 - (void)goToItem:(NSUInteger)index;
 - (void)createButtons;
 //UI actions
-- (IBAction)usePipe:(id)sender;
-- (IBAction)enterServerIP:(id)sender;
 - (void)printContent;
-- (void)cycleDeviceType;
+- (void)presentOptions;
 
 //SplitView popover management
 - (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
diff --git a/experimental/iOSSampleApp/Shared/SkUIDetailViewController.mm b/experimental/iOSSampleApp/Shared/SkUIDetailViewController.mm
index c0f4990..95aa88e 100644
--- a/experimental/iOSSampleApp/Shared/SkUIDetailViewController.mm
+++ b/experimental/iOSSampleApp/Shared/SkUIDetailViewController.mm
@@ -4,26 +4,30 @@
 #include "SkApplication.h"
 #include "SkCGUtils.h"
 #include "SkData.h"
+#include "SkOSMenu.h"
 @implementation SkUIDetailViewController
-@synthesize fNavigationBar, fPrintButton, fCycleButton, fPopOverController;
+@synthesize fPrintButton, fOptionsButton, fPopOverController, fOptionsController;
 
 //Overwritten from UIViewController
 - (void)viewDidLoad {
     [super viewDidLoad];
 
     fSkUIView = (SkUIView*)self.view;
+    
     fWind = (SampleWindow*)fSkUIView.fWind;
-    fSkUIView.fTitleItem = fNavigationBar.topItem;
-
-    [NSTimer scheduledTimerWithTimeInterval:0.001 target:self
-                                   selector:@selector(redraw) userInfo:nil
-                                    repeats:YES];
+    fSkUIView.fTitleItem = self.navigationItem;
+    
     [self createButtons];
+    
+    fOptionsController = [[SkOptionsTableViewController alloc] 
+                          initWithStyle:UITableViewStyleGrouped];
+    fSkUIView.fOptionsDelegate = fOptionsController;
+    [fOptionsController registerMenus:fWind->getMenus()];
 }
 
 - (void)createButtons {
     UIToolbar* toolbar = [[UIToolbar alloc]
-                          initWithFrame:CGRectMake(0, 0, 150, 45)];
+                          initWithFrame:CGRectMake(0, 0, 125, 45)];
     [toolbar setBarStyle: UIBarStyleBlackOpaque];
     
     UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc]
@@ -31,12 +35,11 @@
                                        target:nil
                                        action:nil];
     
-    fCycleButton = [[UIBarButtonItem alloc]
-                    initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
+    fOptionsButton = [[UIBarButtonItem alloc]
+                    initWithTitle:@"Options" 
+                    style:UIBarButtonItemStylePlain
                     target:self
-                    action:@selector(cycleDeviceType)];
-    fCycleButton.style = UIBarButtonItemStylePlain;
-    
+                    action:@selector(presentOptions)];
     UIBarButtonItem* fixedSpace = [[UIBarButtonItem alloc]
                                     initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                     target:nil
@@ -49,7 +52,7 @@
                     action:@selector(printContent)];
     fPrintButton.style = UIBarButtonItemStylePlain;
 
-    [toolbar setItems:[NSArray arrayWithObjects:flexibleSpace, fCycleButton, fixedSpace, fPrintButton, nil]
+    [toolbar setItems:[NSArray arrayWithObjects:flexibleSpace, fOptionsButton, fixedSpace, fPrintButton, nil]
              animated:NO];
     
     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
@@ -64,19 +67,15 @@
 }
 
 - (void)dealloc {
-    [fNavigationBar release];
     [fPrintButton release];
-    [fCycleButton release];
+    [fOptionsButton release];
     [fPopOverController release];
+    [fOptionsController release];
     application_term();
     [super dealloc];
 }
 
 //Instance Methods
-- (void)redraw {
-    [self.view setNeedsDisplay];
-}
-
 - (void)populateRoot:(SkUIRootViewController*)rootVC {
     for (int i = 0; i < fWind->sampleCount(); ++i) {
         [rootVC addItem:[NSString stringWithUTF8String:fWind->getSampleTitle(i).c_str()]];
@@ -87,11 +86,6 @@
     fWind->goToSample(index);
 }
 
-//UI actions
-- (IBAction)usePipe:(id)sender {
-    //fWind->togglePipe();
-}
-
 - (void)printContent {
     UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
     UIPrintInfo *printInfo = [UIPrintInfo printInfo];
@@ -123,57 +117,42 @@
     }
 }
 
-- (IBAction)enterServerIP:(id)sender {
-    SkAlertPrompt *prompt = [[SkAlertPrompt alloc] initWithTitle:@"Enter Server IP:"
-                                                         message:@"\n"
-                                                        delegate:self
-                                               cancelButtonTitle:@"Cancel"
-                                               otherButtonTitles:@"Enter", nil];
-    // show the dialog box
-    [prompt show];
-    [prompt release];
-}
-
-- (void)cycleDeviceType {
-    fWind->toggleRendering();
-}
-
-/*
-- (void)presentActions {
-    if (!fPopOverController) {
-        SkOptionsTableViewController* controller = [[SkOptionsTableViewController alloc] 
-                                                    initWithStyle:UITableViewStyleGrouped];
-        fPopOverController = [[UIPopoverController alloc] initWithContentViewController:controller];
-        fPopOverController.popoverContentSize = CGSizeMake(500, 400);
-        [controller release];
-    }
-    
-    if (fPopOverController.isPopoverVisible)
-        [fPopOverController dismissPopoverAnimated:YES];
-    else
-        [fPopOverController presentPopoverFromBarButtonItem:fPrintButton 
-                                   permittedArrowDirections:UIPopoverArrowDirectionAny 
-                                                   animated:YES];
-
-}
- */
-
-// manage popup
-- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
-{
-    if (buttonIndex != [alertView cancelButtonIndex])
-    {
-        NSString *entered = [(SkAlertPrompt*)alertView enteredText];
-        //fWind->setServerIP([entered UTF8String]);
+- (void)presentOptions {
+    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+        if (nil == fPopOverController) {
+            UINavigationController* navigation = [[UINavigationController alloc] 
+                                                  initWithRootViewController:fOptionsController];
+            navigation.navigationBar.topItem.title = @"Options";
+            fPopOverController = [[UIPopoverController alloc] initWithContentViewController:navigation];
+            [navigation release];
+        }
+        
+        if (fPopOverController.isPopoverVisible)
+            [fPopOverController dismissPopoverAnimated:YES];
+        else
+            [fPopOverController presentPopoverFromBarButtonItem:fOptionsButton 
+                                       permittedArrowDirections:UIPopoverArrowDirectionAny 
+                                                       animated:YES];
+        
+    } else {
+        UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
+                                                                       style:UIBarButtonItemStyleBordered
+                                                                      target:nil
+                                                                      action:nil];
+        self.navigationItem.backBarButtonItem = backButton;
+        [backButton release];
+        [self.navigationController pushViewController:fOptionsController animated:YES];
+        self.navigationController.navigationBar.topItem.title = @"Options";
     }
 }
+ 
 //Popover Management
 - (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
-    [fNavigationBar.topItem setLeftBarButtonItem:barButtonItem animated:NO];
+    [self.navigationItem setLeftBarButtonItem:barButtonItem animated:NO];
 }
 
 - (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
-    [fNavigationBar.topItem setLeftBarButtonItem:nil animated:NO];
+    [self.navigationItem setLeftBarButtonItem:nil animated:NO];
 }
 
 @end
\ No newline at end of file
diff --git a/experimental/iOSSampleApp/Shared/SkUIRootViewController.h b/experimental/iOSSampleApp/Shared/SkUIRootViewController.h
index 80c60e8..e4deec1 100644
--- a/experimental/iOSSampleApp/Shared/SkUIRootViewController.h
+++ b/experimental/iOSSampleApp/Shared/SkUIRootViewController.h
@@ -16,7 +16,6 @@
 @property (nonatomic, retain) UIPopoverController *popoverController;
 @property (nonatomic, retain) UIBarButtonItem *popoverButtonItem;
 
-- (void)initSamples;
 - (void)addItem:(NSString*)anItem;
 
 @end
diff --git a/experimental/iOSSampleApp/Shared/SkUIRootViewController.mm b/experimental/iOSSampleApp/Shared/SkUIRootViewController.mm
index b0b22e6..255a271 100644
--- a/experimental/iOSSampleApp/Shared/SkUIRootViewController.mm
+++ b/experimental/iOSSampleApp/Shared/SkUIRootViewController.mm
@@ -7,6 +7,7 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
     self.contentSizeForViewInPopover = CGSizeMake(200, self.view.bounds.size.height);
+    fSamples = [[NSMutableArray alloc] init];
 }
 
 - (void)viewDidUnload {
@@ -56,9 +57,5 @@
     [fSamples addObject:anItem];
 }
 
-- (void)initSamples {
-    fSamples = [[NSMutableArray alloc] init];
-}
-
 @end
 
diff --git a/experimental/iOSSampleApp/Shared/SkUIView.h b/experimental/iOSSampleApp/Shared/SkUIView.h
index 33c487e..76d660d 100644
--- a/experimental/iOSSampleApp/Shared/SkUIView.h
+++ b/experimental/iOSSampleApp/Shared/SkUIView.h
@@ -19,13 +19,18 @@
 class SkOSWindow;
 class SkEvent;
 struct FPSState;
-@interface SkUIView : UIView <UIAccelerometerDelegate> {
+@class SkUIView;
+
+@protocol SkUIViewOptionsDelegate <NSObject>
+@optional
+// Called when the view needs to handle adding an SkOSMenu
+- (void) view:(SkUIView*)view didAddMenu:(const SkOSMenu*)menu;
+- (void) view:(SkUIView*)view didUpdateMenu:(const SkOSMenu*)menu;
+@end
+
+@interface SkUIView : UIView  {
     BOOL fRedrawRequestPending;
-    SkMatrix    fMatrix;
-
-    float       fZoomAroundX, fZoomAroundY;
-    bool        fZoomAround;
-
+    
     struct {
         EAGLContext*    fContext;
         GLuint          fRenderbuffer;
@@ -35,26 +40,30 @@
         GLint           fHeight;
     } fGL;
     
-    FPSState* fFPSState;
     NSString* fTitle;
     UINavigationItem* fTitleItem;
-    SkOSWindow* fWind;
     CALayer* fRasterLayer;
     CAEAGLLayer* fGLLayer;
     
+    FPSState* fFPSState;
+    SkOSWindow* fWind;
     SkiOSDeviceManager* fDevManager;
+    
+    id<SkUIViewOptionsDelegate> fOptionsDelegate;
 }
 
-@property (nonatomic, assign) SkOSWindow *fWind;
+@property (nonatomic, readonly) SkOSWindow *fWind;
 @property (nonatomic, retain) UINavigationItem* fTitleItem;
 @property (nonatomic, copy) NSString* fTitle;
 @property (nonatomic, retain) CALayer* fRasterLayer;
 @property (nonatomic, retain) CAEAGLLayer* fGLLayer;
+@property (nonatomic, assign) id<SkUIViewOptionsDelegate> fOptionsDelegate;
 
 - (void)forceRedraw;
 
 - (void)setSkTitle:(const char*)title;
+- (void)onAddMenu:(const SkOSMenu*)menu;
+- (void)onUpdateMenu:(const SkOSMenu*)menu;
 - (void)postInvalWithRect:(const SkIRect*)rectOrNil;
 - (BOOL)onHandleEvent:(const SkEvent&)event;
-@end
-
+@end
\ No newline at end of file
diff --git a/experimental/iOSSampleApp/Shared/SkUIView.mm b/experimental/iOSSampleApp/Shared/SkUIView.mm
index 77cab50..d60763e 100644
--- a/experimental/iOSSampleApp/Shared/SkUIView.mm
+++ b/experimental/iOSSampleApp/Shared/SkUIView.mm
@@ -5,7 +5,7 @@
 #define SKGL_CONFIG         kEAGLColorFormatRGB565
 //#define SKGL_CONFIG         kEAGLColorFormatRGBA8
 
-#define FORCE_REDRAW
+//#define FORCE_REDRAW
 
 //#define USE_GL_1
 #define USE_GL_2
@@ -84,7 +84,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 @implementation SkUIView
 
-@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer;
+@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer, fOptionsDelegate;
 
 #include "SkApplication.h"
 #include "SkEvent.h"
@@ -171,7 +171,6 @@
 - (id)initWithMyDefaults {
     fRedrawRequestPending = false;
     fFPSState = new FPSState;
-    
 #ifdef USE_GL_1
     fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
 #else
@@ -197,7 +196,7 @@
     glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
 
-    fGLLayer = [CAEAGLLayer layer];
+    self.fGLLayer = [CAEAGLLayer layer];
     fGLLayer.bounds = self.bounds;
     fGLLayer.anchorPoint = CGPointMake(0, 0);
     fGLLayer.opaque = TRUE;
@@ -209,7 +208,7 @@
                                    kEAGLDrawablePropertyColorFormat,
                                    nil];
     
-    fRasterLayer = [CALayer layer];
+    self.fRasterLayer = [CALayer layer];
     fRasterLayer.anchorPoint = CGPointMake(0, 0);
     fRasterLayer.opaque = TRUE;
     [self.layer addSublayer:fRasterLayer];
@@ -228,9 +227,6 @@
     fWind = new SampleWindow(self, NULL, NULL, fDevManager);
     application_init();
     fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
-    fMatrix.reset();
-    fZoomAround = false;
-
     return self;
 }
 
@@ -252,8 +248,9 @@
     delete fWind;
     delete fDevManager;
     delete fFPSState;
-    [fRasterLayer release];
-    [fGLLayer release];
+    self.fRasterLayer = nil;
+    self.fGLLayer = nil;
+    [fGL.fContext release];
     application_term();
     [fTitleItem release];
     [super dealloc];
@@ -420,6 +417,14 @@
     return false;
 }
 
+#include "SkOSMenu.h"
+- (void)onAddMenu:(const SkOSMenu*)menu {
+    [self.fOptionsDelegate view:self didAddMenu:menu];
+}
+- (void)onUpdateMenu:(const SkOSMenu*)menu {
+    [self.fOptionsDelegate view:self didUpdateMenu:menu];
+}
+
 - (void)postInvalWithRect:(const SkIRect*)r {
     if (!fRedrawRequestPending) {
         fRedrawRequestPending = true;
@@ -434,6 +439,7 @@
         }
         else {
             [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
+            [self setNeedsDisplay];
         }
     }
 }
diff --git a/experimental/iOSSampleApp/Shared/SkiOSDeviceManager.h b/experimental/iOSSampleApp/Shared/SkiOSDeviceManager.h
new file mode 100644
index 0000000..da4975c
--- /dev/null
+++ b/experimental/iOSSampleApp/Shared/SkiOSDeviceManager.h
@@ -0,0 +1,36 @@
+#ifndef SkiOSDeviceManager_DEFINED
+#define SkiOSDeviceManager_DEFINED
+#include "SampleApp.h"
+#include "SkCanvas.h"
+#include "GrContext.h"
+#include "GrGLInterface.h"
+#include "SkGpuDevice.h"
+#include "SkCGUtils.h"
+#include "GrContext.h"
+class SkiOSDeviceManager : public SampleWindow::DeviceManager {
+public:
+    SkiOSDeviceManager();
+    virtual ~SkiOSDeviceManager();
+    
+    virtual void init(SampleWindow* win);
+    
+    virtual bool supportsDeviceType(SampleWindow::DeviceType dType);
+    virtual bool prepareCanvas(SampleWindow::DeviceType dType,
+                               SkCanvas* canvas,
+                               SampleWindow* win);
+    virtual void publishCanvas(SampleWindow::DeviceType dType,
+                               SkCanvas* canvas,
+                               SampleWindow* win);
+    
+    virtual void windowSizeChanged(SampleWindow* win) {}
+    
+    bool isUsingGL() { return usingGL; }
+    
+    virtual GrContext* getGrContext() { return fGrContext; }
+private:
+    bool usingGL;
+    GrContext* fGrContext;
+    GrRenderTarget* fGrRenderTarget;
+};
+
+#endif
\ No newline at end of file
diff --git a/experimental/iOSSampleApp/Shared/SkiOSNotifier.h b/experimental/iOSSampleApp/Shared/SkiOSNotifier.h
deleted file mode 100644
index dcad27c..0000000
--- a/experimental/iOSSampleApp/Shared/SkiOSNotifier.h
+++ /dev/null
@@ -1,14 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#import <Foundation/Foundation.h>
-
-@interface SkIOSNotifier : NSObject
-- (void)receiveSkEvent:(NSNotification*)notification;
-+ (void)postTimedSkEvent:(NSTimeInterval)ti;
-+ (void)timerFireMethod:(NSTimer*)theTimer;
-@end
diff --git a/experimental/iOSSampleApp/Shared/SkiOSNotifier.mm b/experimental/iOSSampleApp/Shared/SkiOSNotifier.mm
deleted file mode 100644
index 5c2bc55..0000000
--- a/experimental/iOSSampleApp/Shared/SkiOSNotifier.mm
+++ /dev/null
@@ -1,58 +0,0 @@
-#import "SkIOSNotifier.h"
-#import "SkEvent.h"
-#define SkEventClass @"SkEvenClass"
-@implementation SkIOSNotifier
-//Overwritten from NSObject
-- (id)init {
-    self = [super init];
-    if (self) {
-        //Register as an observer for SkEventClass events and call
-        //receiveSkEvent: upon receiving the event
-        [[NSNotificationCenter defaultCenter] addObserver:self
-                                                 selector:@selector(receiveSkEvent:)
-                                                     name:SkEventClass
-                                                   object:nil];
-    }
-    return self;
-}
-
-- (void)dealloc {
-    [[NSNotificationCenter defaultCenter] removeObserver:self];
-    [super dealloc];
-}
-
--(BOOL) acceptsFirstResponder {
-    return YES;
-}
-
-//SkEvent Handers
-- (void)receiveSkEvent:(NSNotification *)notification {
-    if(SkEvent::ProcessEvent())
-        SkEvent::SignalNonEmptyQueue();
-}
-
-+ (void)postTimedSkEvent:(NSTimeInterval)timeInterval {
-    [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self
-                                   selector:@selector(timerFireMethod:)
-                                   userInfo:nil repeats:NO];
-}
-
-+ (void)timerFireMethod:(NSTimer*)theTimer {
-	SkEvent::ServiceQueueTimer();
-}
-
-@end
-////////////////////////////////////////////////////////////////////////////////
-void SkEvent::SignalNonEmptyQueue() {
-    //post a SkEventClass event to the default notification center
-    [[NSNotificationCenter defaultCenter] postNotificationName:SkEventClass
-                                                        object:nil];
-}
-
-void SkEvent::SignalQueueTimer(SkMSec delay) {
-	if (delay) {
-        //Convert to seconds
-        NSTimeInterval ti = delay/(float)SK_MSec1;
-        [SkIOSNotifier postTimedSkEvent:ti];
-	}
-}