From fd5620eae36c0ce5b3c9ca5d001e326d59775fcd Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Wed, 15 May 2013 21:21:09 -0400 Subject: [PATCH 01/18] Allow user to specify a UIImage as the title for a nav bar button item. --- lib/ProMotion/screens/_screen_module.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb index 7de8e43..05ccef2 100644 --- a/lib/ProMotion/screens/_screen_module.rb +++ b/lib/ProMotion/screens/_screen_module.rb @@ -70,13 +70,17 @@ module ProMotion args[:title] = title set_nav_bar_button :left, args end - + def set_nav_bar_button(side, args={}) args[:style] ||= UIBarButtonItemStyleBordered args[:target] ||= self args[:action] ||= nil - button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action]) + if args[:title].is_a?(UIImage) + button = UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action]) + else + button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action]) + end self.navigationItem.leftBarButtonItem = button if side == :left self.navigationItem.rightBarButtonItem = button if side == :right From 5abd3481beff33011f5c733ee2aad6d91a97b1c1 Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 09:17:59 -0400 Subject: [PATCH 02/18] Update readme to note that UIImages can be sent to create UIBarButtons --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c36f34d..8d81170 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,8 @@ set_nav_bar_right_button "Save", action: :save_something, type: UIBarButtonItemS set_nav_bar_left_button "Cancel", action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain ``` +If you pass an instance of a `UIImage`, the `UIBarButton` will automatically display with that image instead of text. *Don't forget retina and landscape versions of your image!* + ## Opening and closing screens If the user taps something and you want to open a new screen, it's easy. Just use `open` and pass in the screen class @@ -284,7 +286,6 @@ class ProfileScreen < ProMotion::Screen self.user # => some_user instance end end - ``` Closing a screen is as easy as can be. @@ -564,12 +565,14 @@ end set_nav_bar_left_button(title, args = {}) Set a left nav bar button.
+ `title` can be a `String` or a `UIImage`. set_nav_bar_right_button(title, args = {}) Set a right nav bar button.
+ `title` can be a `String` or a `UIImage`. From 2e8697e9b55a85e2940cf6426fa7a4c4c4c4d69a Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 09:34:45 -0400 Subject: [PATCH 03/18] Update test app rakefile for RM2.0 syntax --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 37bb157..34e30b9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ $:.unshift("/Library/RubyMotion/lib") -require 'motion/project' +require 'motion/project/template/ios' require 'bundler/gem_tasks' Bundler.setup Bundler.require From 8acdeaf7cd3515d4f2ce15c37627c33087541c4d Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 09:35:08 -0400 Subject: [PATCH 04/18] Add tests for creating a UIBarButton with a UIImage. --- resources/list.png | Bin 0 -> 104 bytes spec/helpers/home_screen.rb | 4 ++-- spec/screen_helpers_spec.rb | 15 ++++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100755 resources/list.png diff --git a/resources/list.png b/resources/list.png new file mode 100755 index 0000000000000000000000000000000000000000..263cffd387c6486ab1a0d8969b304754bc3277eb GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^;y^6S!3HF&cTd{}r1U*q978H@y}f8C$iTpH_<)xa z(?4HEWwuRA%OiK! Date: Thu, 16 May 2013 09:37:51 -0400 Subject: [PATCH 05/18] One more test to make sure it's the RIGHT image ;) --- spec/screen_helpers_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/screen_helpers_spec.rb b/spec/screen_helpers_spec.rb index cff3c71..72bd300 100644 --- a/spec/screen_helpers_spec.rb +++ b/spec/screen_helpers_spec.rb @@ -55,8 +55,10 @@ describe "screen helpers" do end it "should add an image right nav bar button" do - @screen.set_nav_bar_right_button UIImage.imageNamed("list.png"), action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain + image = UIImage.imageNamed("list.png") + @screen.set_nav_bar_right_button image, action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain @screen.navigationItem.rightBarButtonItem.image.class.should == UIImage + @screen.navigationItem.rightBarButtonItem.image.should == image end end From 3f74b18a4c4d8ef49dc6a7e94b9ebe8ed1bdbdb3 Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 10:39:09 -0400 Subject: [PATCH 06/18] Added Winston-Salem Crime Map to the list of apps that use ProMotion. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c36f34d..90fee9a 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ App Store to see what's possible. ClearSight Studio built the app for Kijome Sof ### TipCounter App [TipCounter](http://www.tipcounterapp.com) was built by [Matt Brewer](https://github.com/macfanatic/) for bartenders and servers to easily track their tips. Used ProMotion and the development was a lot of fun! +### Winston-Salem Crime Map +Have an interest in crime statistics and locations? Live in Winston-Salem, NC? This hyper-local and [open source](https://github.com/markrickert/WSCrime) RubyMotion app uses a mixture custom UIViewControllers and ProMotion for ease of attribute setting and adding views. Check it out [on the App Store](http://www.mohawkapps.com/winston-salem-crime-map/download/) or [fork it and contribute](https://github.com/markrickert/WSCrime)! + # Getting Started ProMotion is designed to be as intuitive and Ruby-like as possible. For example, here is a From 4117fe9e92b1007fd72c85cfd948012a9d176626 Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 12:22:10 -0400 Subject: [PATCH 07/18] Added tests for the left bar button item. --- spec/screen_helpers_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/screen_helpers_spec.rb b/spec/screen_helpers_spec.rb index 72bd300..ae6c14f 100644 --- a/spec/screen_helpers_spec.rb +++ b/spec/screen_helpers_spec.rb @@ -61,6 +61,13 @@ describe "screen helpers" do @screen.navigationItem.rightBarButtonItem.image.should == image end + it "should add an image left nav bar button" do + image = UIImage.imageNamed("list.png") + @screen.set_nav_bar_left_button image, action: :return_to_some_other_screen, type: UIBarButtonItemStylePlain + @screen.navigationItem.leftBarButtonItem.image.class.should == UIImage + @screen.navigationItem.leftBarButtonItem.image.should == image + end + end describe "screen navigation" do From c67563b50601d2f829c5cf451aa045d4e14684c9 Mon Sep 17 00:00:00 2001 From: Jamon Holmgren Date: Thu, 16 May 2013 10:00:34 -0700 Subject: [PATCH 08/18] Clarified app_delegate code --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 90fee9a..144ef80 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ gem "ProMotion", "~> 0.6.0" Run `bundle install` in Terminal to install ProMotion. -Go into your app/app_delegate.rb file and add the following: +Go into your app/app_delegate.rb file and replace everything with the following: ```ruby class AppDelegate < ProMotion::Delegate @@ -121,6 +121,9 @@ class AppDelegate < ProMotion::Delegate end ``` +Make sure you remove the `didFinishLoadingWithOptions` method or call `super` in it. Otherwise +ProMotion won't get set up and `on_load` won't be called. + Create a folder in `/app` named `screens`. Create a file in that folder named `home_screen.rb`. Now drop in this code: From 75e187381530d940546582ce0ae71e4fa0418067 Mon Sep 17 00:00:00 2001 From: Jamon Holmgren Date: Thu, 16 May 2013 10:57:23 -0700 Subject: [PATCH 09/18] Switched demo app link --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ed0df5e..f60246b 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,9 @@ http://www.clearsightstudio.com/insights/tutorial-make-youtube-video-app-rubymot ## Sample Apps -[https://github.com/jamonholmgren/promotion-tutorial](https://github.com/jamonholmgren/promotion-tutorial) +This is pretty bare-bones, but we'll be building it out as we go along. + +[https://github.com/jamonholmgren/promotion-demo](https://github.com/jamonholmgren/promotion-demo) ## Apps Built With ProMotion From 543ba8060ca3e867b35453168ab2c98b5472b41b Mon Sep 17 00:00:00 2001 From: Steve Ross Date: Thu, 16 May 2013 11:09:45 -0700 Subject: [PATCH 10/18] Changed set_nav_bar_button to accept a system_icon hash key that allows creation of system buttons like add. --- lib/ProMotion/screens/_screen_module.rb | 10 ++++++++-- spec/screen_spec.rb | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb index 7de8e43..9eadea6 100644 --- a/lib/ProMotion/screens/_screen_module.rb +++ b/lib/ProMotion/screens/_screen_module.rb @@ -71,12 +71,18 @@ module ProMotion set_nav_bar_button :left, args end + # If you call set_nav_bar_button with a nil title and system_icon: UIBarButtonSystemItemAdd (or any other + # system icon), the button is initialized with a barButtonSystemItem instead of a title. def set_nav_bar_button(side, args={}) args[:style] ||= UIBarButtonItemStyleBordered args[:target] ||= self args[:action] ||= nil - - button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action]) + + if args[:system_icon] + button = UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) + else + button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action]) + end self.navigationItem.leftBarButtonItem = button if side == :left self.navigationItem.rightBarButtonItem = button if side == :right diff --git a/spec/screen_spec.rb b/spec/screen_spec.rb index 4ca5932..da80eac 100644 --- a/spec/screen_spec.rb +++ b/spec/screen_spec.rb @@ -108,4 +108,18 @@ describe "screen properties" do end + describe "bar button behavior" do + before do + @screen.set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd + end + + it "has a right bar button item of the correct type" do + @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem + end + + it "is an add button" do + @screen.navigationItem.rightBarButtonItem.action.should == :add_something + end + end + end From f7eeeb7d1a9047b42451c5f8db2fba1a9d407b5c Mon Sep 17 00:00:00 2001 From: Mark Rickert Date: Thu, 16 May 2013 14:11:15 -0400 Subject: [PATCH 11/18] Fix linebreak in the readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d81170..e0c8fe8 100644 --- a/README.md +++ b/README.md @@ -572,7 +572,7 @@ end set_nav_bar_right_button(title, args = {}) Set a right nav bar button.
- `title` can be a `String` or a `UIImage`. + `title` can be a `String` or a `UIImage`.
From e0b0f7329b17bc60aa52b6d66509e7df6cf8b9be Mon Sep 17 00:00:00 2001 From: Steve Ross Date: Thu, 16 May 2013 12:50:03 -0700 Subject: [PATCH 12/18] Fixed system item in set_bar_bar_button to take UIImage change into account; updated README --- README.md | 68 ++++++++++++++----------- lib/ProMotion/screens/_screen_module.rb | 17 ++++--- spec/screen_spec.rb | 52 ++++++++++++++++--- 3 files changed, 91 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index f60246b..93c7f15 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ProMotion is a RubyMotion gem that makes iOS development more like Ruby and less - [Working on Features](#working-on-features) - [Submitting a Pull Request](#submitting-a-pull-request) - [Primary Contributors](#primary-contributors) - + # Tutorials http://www.clearsightstudio.com/insights/ruby-motion-promotion-tutorial @@ -57,7 +57,7 @@ This is pretty bare-bones, but we'll be building it out as we go along. ## Apps Built With ProMotion ### BigDay! Reminder App -Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the +Check out the free [BigDay! Reminder app](https://itunes.apple.com/us/app/bigday!/id571756685?ls=1&mt=8) on the App Store to see what's possible. ClearSight Studio built the app for Kijome Software, a small app investment company. ### TipCounter App @@ -68,7 +68,7 @@ Have an interest in crime statistics and locations? Live in Winston-Salem, NC? T # Getting Started -ProMotion is designed to be as intuitive and Ruby-like as possible. For example, here is a +ProMotion is designed to be as intuitive and Ruby-like as possible. For example, here is a typical app folder structure: app/ @@ -133,7 +133,7 @@ Now drop in this code: ```ruby class HomeScreen < ProMotion::Screen title "Home" - + def will_appear set_attributes self.view, { backgroundColor: UIColor.whiteColor @@ -173,12 +173,12 @@ class HomeScreen < ProMotion::Screen def on_load # Load data end - + def will_appear # Set up the elements in your view with add @label ||= add UILabel.alloc.initWithFrame(CGRectMake(5, 5, 20, 20)) end - + def on_appear # Everything's loaded and visible end @@ -217,18 +217,18 @@ def on_load(app, options) @home = MyHomeScreen.new(nav_bar: true) @settings = SettingsScreen.new @contact = ContactScreen.new(nav_bar: true) - + open_tab_bar @home, @settings, @contact end ``` -For each screen that belongs to the tab bar, you need to set the tab name and icon in the files. +For each screen that belongs to the tab bar, you need to set the tab name and icon in the files. In this example, we would need add the following to the three files (my_home_screen.rb, settings_screen.rb, contact_screen.rb): ```ruby def on_load set_tab_bar_item title: "Tab Name Goes Here", icon: "icons/tab_icon.png" # in resources/icons folder - + # or... set_tab_bar_item system_icon: UITabBarSystemItemContacts end @@ -254,6 +254,12 @@ set_nav_bar_left_button "Cancel", action: :return_to_some_other_screen, type: UI If you pass an instance of a `UIImage`, the `UIBarButton` will automatically display with that image instead of text. *Don't forget retina and landscape versions of your image!* +If you pass `:system` for the title, then you can get a system item. E.g.: + +```ruby +set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd +``` + ## Opening and closing screens If the user taps something and you want to open a new screen, it's easy. Just use `open` and pass in the screen class @@ -403,7 +409,7 @@ class SettingsScreen < ProMotion::GroupedTableScreen add_right_nav_button(label: "Save", action: :save) set_tab_bar_item(title: "Settings", icon: "settings.png") end - + # table_data is automatically called. Use this format in the return value. # It's an array of cell groups, each cell group consisting of a title and an array of cells. def table_data @@ -427,10 +433,10 @@ class SettingsScreen < ProMotion::GroupedTableScreen def table_data_index # Ruby magic to make an alphabetical array of letters. # Try this in Objective-C and tell me you want to go back. - return ("A".."Z").to_a + return ("A".."Z").to_a end - - # Your table cells, when tapped, will execute the corresponding actions + + # Your table cells, when tapped, will execute the corresponding actions # and pass in the specified arguments. def edit_profile(args={}) puts args[:id] # => 3 @@ -438,7 +444,7 @@ class SettingsScreen < ProMotion::GroupedTableScreen end ``` -You can provide remotely downloaded images for cells by including the CocoaPod "SDWebImage" in +You can provide remotely downloaded images for cells by including the CocoaPod "SDWebImage" in your Rakefile and doing this: ```ruby @@ -453,9 +459,9 @@ your Rakefile and doing this: ## Using your own UIViewController Sometimes you want to inherit from a different UIViewController other than that provided by ProMotion, -such as when using [Formotion](https://github.com/clayallsopp/formotion). **RubyMotion doesn't currently -allow us to override built-in methods when including them as a module.** And we really need to override -`viewDidLoad` and others. +such as when using [Formotion](https://github.com/clayallsopp/formotion). **RubyMotion doesn't currently +allow us to override built-in methods when including them as a module.** And we really need to override +`viewDidLoad` and others. Fortunately, there's a workaround for that. @@ -479,15 +485,15 @@ class EventsScreen < Formotion::FormController # Can also be < UIViewController super self.view_did_appear(animated) if self.respond_to?("view_did_appear:") end - + def viewWillDisappear(animated) self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:") super end - + def viewDidDisappear(animated) self.view_did_disappear(animated) if self.respond_to?("view_did_disappear:") - super + super end def shouldAutorotateToInterfaceOrientation(orientation) @@ -501,7 +507,7 @@ class EventsScreen < Formotion::FormController # Can also be < UIViewController def willRotateToInterfaceOrientation(orientation, duration:duration) self.will_rotate(orientation, duration) end - + def didRotateFromInterfaceOrientation(orientation) self.on_rotate end @@ -535,13 +541,13 @@ end Creates the tab that is shown in a tab bar item.
Arguments: { icon: "imagename", systemIcon: UISystemIconContacts, title: "tabtitle" } - + on_appear Callback for when the screen appears.
- + will_appear @@ -611,7 +617,7 @@ end

 class SomeScreen
   title "Some screen"
-  
+
   def on_load
     # ...
   end
@@ -732,9 +738,9 @@ end
   
     
refreshable(
   callback: :on_refresh,
-  pull_message: "Pull to refresh", 
-  refreshing: "Refreshing data…", 
-  updated_format: "Last updated at %s", 
+  pull_message: "Pull to refresh",
+  refreshing: "Refreshing data…",
+  updated_format: "Last updated at %s",
   updated_time_format: "%l:%M %p"
 )
Class method to make the current table refreshable. @@ -756,7 +762,7 @@ end
Performance note... It's best to build this array in a different method and store it in something like @table_data. Then your table_data method just returns that. - +

 def table_data
   [{
@@ -771,7 +777,7 @@ def table_data
       arguments: { data: [ "lots", "of", "data" ] },
       action: :tapped_cell_1,
       height: 50, # manually changes the cell's height
-      cell_style: UITableViewCellStyleSubtitle, 
+      cell_style: UITableViewCellStyleSubtitle,
       cell_identifier: "Cell",
       cell_class: ProMotion::TableViewCell,
       masks_to_bounds: true,
@@ -787,7 +793,7 @@ def table_data
       accessory_checked: true, # whether it's "checked" or not
       image: { image: UIImage.imageNamed("something"), radius: 15 },
       remote_image: {  # remote image, requires SDWebImage CocoaPod
-        url: "http://placekitten.com/200/300", placeholder: "some-local-image", 
+        url: "http://placekitten.com/200/300", placeholder: "some-local-image",
         size: 50, radius: 15
       },
       subviews: [ @some_view, @some_other_view ] # arbitrary views added to the cell
@@ -891,7 +897,7 @@ Opening a ticket is usually the best and we respond to those pretty quickly.
 
 # Contributing
 
-I'm very open to ideas. Tweet me with your ideas or open a ticket (I don't mind!) 
+I'm very open to ideas. Tweet me with your ideas or open a ticket (I don't mind!)
 and let's discuss.
 
 ## Working on Features
diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb
index 716a4d9..b4abe11 100644
--- a/lib/ProMotion/screens/_screen_module.rb
+++ b/lib/ProMotion/screens/_screen_module.rb
@@ -70,20 +70,23 @@ module ProMotion
       args[:title] = title
       set_nav_bar_button :left, args
     end
-    
+
     # If you call set_nav_bar_button with a nil title and system_icon: UIBarButtonSystemItemAdd (or any other
     # system icon), the button is initialized with a barButtonSystemItem instead of a title.
     def set_nav_bar_button(side, args={})
       args[:style]  ||= UIBarButtonItemStyleBordered
       args[:target] ||= self
       args[:action] ||= nil
-      
-      button = UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) if args[:system_icon]
 
-      if args[:title].is_a?(UIImage)
-        button = UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action])
-      else
-        button = UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action])
+      button = case args[:title]
+        when String
+          UIBarButtonItem.alloc.initWithTitle(args[:title], style: args[:style], target: args[:target], action: args[:action])
+        when UIImage
+          UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action])
+        when Symbol, NilClass
+          UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) if args[:system_icon]
+        else
+          PM.logger.error("Please supply a title string, a UIImage or :system.")
       end
 
       self.navigationItem.leftBarButtonItem = button if side == :left
diff --git a/spec/screen_spec.rb b/spec/screen_spec.rb
index da80eac..f493134 100644
--- a/spec/screen_spec.rb
+++ b/spec/screen_spec.rb
@@ -73,10 +73,10 @@ describe "screen properties" do
     end
 
     it "-willRotateToInterfaceOrientation" do
-      @screen.mock! :will_rotate do |orientation, duration| 
+      @screen.mock! :will_rotate do |orientation, duration|
         orientation.should == UIInterfaceOrientationPortrait
         duration.should == 0.5
-      end 
+      end
       @screen.willRotateToInterfaceOrientation(UIInterfaceOrientationPortrait, duration: 0.5)
     end
 
@@ -109,17 +109,53 @@ describe "screen properties" do
   end
 
   describe "bar button behavior" do
-    before do
-      @screen.set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd
+    describe "system bar buttons" do
+      before do
+        @screen.set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "is an add button" do
+        @screen.navigationItem.rightBarButtonItem.action.should == :add_something
+      end
     end
 
-    it "has a right bar button item of the correct type" do
-      @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+    describe 'titled bar buttons' do
+      before do
+        @screen.set_nav_bar_right_button "Save", action: :save_something, style: UIBarButtonItemStyleDone
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "has a right bar button item of the correct style" do
+        @screen.navigationItem.rightBarButtonItem.style.should == UIBarButtonItemStyleDone
+      end
+
+      it "is titled correctly" do
+        @screen.navigationItem.rightBarButtonItem.title.should == 'Save'
+      end
     end
 
-    it "is an add button" do
-      @screen.navigationItem.rightBarButtonItem.action.should == :add_something
+    describe 'image bar buttons' do
+      before do
+        @image = UIImage.alloc.init
+        @screen.set_nav_bar_right_button @image, action: :save_something, style: UIBarButtonItemStyleDone
+      end
+
+      it "has a right bar button item of the correct type" do
+        @screen.navigationItem.rightBarButtonItem.should.be.instance_of UIBarButtonItem
+      end
+
+      it "is has the right image" do
+        @screen.navigationItem.rightBarButtonItem.title.should == nil
+      end
     end
+
   end
 
 end

From 078ba68761af96d21c9354166a86d43fb4487071 Mon Sep 17 00:00:00 2001
From: Matt Brewer 
Date: Fri, 17 May 2013 07:45:37 -0400
Subject: [PATCH 13/18] Added tests to support #74

---
 spec/helpers/screen_module_view_controller.rb |  4 ++++
 spec/screen_module_spec.rb                    | 13 +++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 spec/helpers/screen_module_view_controller.rb
 create mode 100644 spec/screen_module_spec.rb

diff --git a/spec/helpers/screen_module_view_controller.rb b/spec/helpers/screen_module_view_controller.rb
new file mode 100644
index 0000000..593db17
--- /dev/null
+++ b/spec/helpers/screen_module_view_controller.rb
@@ -0,0 +1,4 @@
+class ScreenModuleViewController < UIViewController
+  include PM::ScreenModule
+  title 'Test Title'
+end
diff --git a/spec/screen_module_spec.rb b/spec/screen_module_spec.rb
new file mode 100644
index 0000000..7d1dbd7
--- /dev/null
+++ b/spec/screen_module_spec.rb
@@ -0,0 +1,13 @@
+describe "PM::ScreenModule" do
+
+  before { @subject = ScreenModuleViewController.new }
+
+  it 'should have PM::ScreenModule in ancestors' do
+    @subject.class.ancestors.include?(PM::ScreenModule).should == true
+  end
+
+  it 'should have a title from class method #title' do
+    @subject.title.should == 'Test Title'
+  end
+
+end

From 19d6a4f18182c930ecfa7eb750a15cdb3c3e1ec5 Mon Sep 17 00:00:00 2001
From: Jamon Holmgren 
Date: Fri, 17 May 2013 07:39:45 -0700
Subject: [PATCH 14/18] Fixing specs to work in RM 2.0

https://github.com/clearsightstudio/ProMotion/blob/version-0.6/lib/ProMo
tion/screen_helpers/split_screen.rb#L9
---
 spec/helpers/test_delegate.rb         | 5 -----
 spec/split_screen_in_tab_bar_spec.rb  | 6 +++++-
 spec/split_screen_open_screen_spec.rb | 6 +++++-
 spec/split_screen_spec.rb             | 6 +++++-
 4 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/spec/helpers/test_delegate.rb b/spec/helpers/test_delegate.rb
index 989783b..becdf95 100644
--- a/spec/helpers/test_delegate.rb
+++ b/spec/helpers/test_delegate.rb
@@ -1,9 +1,4 @@
 class TestDelegate < ProMotion::Delegate
   def on_load(app, options)
   end
-
-  # Hack to make RM 2.0 work.
-  # Ref: http://hipbyte.myjetbrains.com/youtrack/issue/RM-136
-  def dealloc
-  end
 end
diff --git a/spec/split_screen_in_tab_bar_spec.rb b/spec/split_screen_in_tab_bar_spec.rb
index 2661351..c21515d 100644
--- a/spec/split_screen_in_tab_bar_spec.rb
+++ b/spec/split_screen_in_tab_bar_spec.rb
@@ -10,6 +10,10 @@ describe "split screen in tab bar functionality" do
     @tab = @app.open_tab_bar @split_screen, HomeScreen, BasicScreen
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should create a UISplitViewController" do
     @split_screen.is_a?(UISplitViewController).should == true
   end
@@ -46,4 +50,4 @@ describe "split screen in tab bar functionality" do
     @tab.viewControllers.first.should == @split_screen
   end
 
-end
\ No newline at end of file
+end
diff --git a/spec/split_screen_open_screen_spec.rb b/spec/split_screen_open_screen_spec.rb
index 0f6ecf1..10bbdb5 100644
--- a/spec/split_screen_open_screen_spec.rb
+++ b/spec/split_screen_open_screen_spec.rb
@@ -10,6 +10,10 @@ describe "split screen `open` functionality" do
     @split_screen = @app.open_split_screen @master_screen, @detail_screen_1
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should open a new screen in the detail view" do
     @master_screen.open @detail_screen_2, in_detail: true
     @split_screen.detail_screen.should == @detail_screen_2
@@ -43,4 +47,4 @@ describe "split screen `open` functionality" do
     home.navigation_controller.topViewController.should == child
   end
 
-end
\ No newline at end of file
+end
diff --git a/spec/split_screen_spec.rb b/spec/split_screen_spec.rb
index 2fd506a..59744b3 100644
--- a/spec/split_screen_spec.rb
+++ b/spec/split_screen_spec.rb
@@ -9,6 +9,10 @@ describe "split screen functionality" do
     @split_screen = @app.open_split_screen @master_screen, @detail_screen
   end
 
+  after do
+    @split_screen.delegate = nil # dereference to avoid memory issue
+  end
+
   it "should have created a split screen" do
     @split_screen.should != nil
     @split_screen.is_a?(UISplitViewController).should == true
@@ -32,4 +36,4 @@ describe "split screen functionality" do
     @split_screen.viewControllers.last.should == @detail_screen.main_controller
   end
 
-end
\ No newline at end of file
+end

From e036935bd6e6a4ea4f8b13b1fefe7637e9a355aa Mon Sep 17 00:00:00 2001
From: Jamon Holmgren 
Date: Fri, 17 May 2013 08:31:40 -0700
Subject: [PATCH 15/18] Cleaning up screen nav specs

Also consolidated where we're checking for main_controller.
---
 .../screen_helpers/screen_navigation.rb       | 21 ++++++-----
 spec/helpers/basic_screen.rb                  |  1 +
 spec/helpers/detail_screen.rb                 |  3 ++
 spec/helpers/master_screen.rb                 |  3 ++
 spec/screen_helpers_spec.rb                   | 14 ++------
 spec/screen_spec.rb                           |  4 +++
 spec/split_screen_spec.rb                     | 36 ++++++++++++++++---
 7 files changed, 57 insertions(+), 25 deletions(-)
 create mode 100644 spec/helpers/detail_screen.rb
 create mode 100644 spec/helpers/master_screen.rb

diff --git a/lib/ProMotion/screen_helpers/screen_navigation.rb b/lib/ProMotion/screen_helpers/screen_navigation.rb
index dcdcd78..cd50e22 100644
--- a/lib/ProMotion/screen_helpers/screen_navigation.rb
+++ b/lib/ProMotion/screen_helpers/screen_navigation.rb
@@ -10,10 +10,13 @@ module ProMotion
       screen.send(:on_load) if screen.respond_to?(:on_load)
       animated = args[:animated] || true
 
-      return self.split_screen.detail_screen = screen if args[:in_detail] && self.split_screen
-      return self.split_screen.master_screen = screen if args[:in_master] && self.split_screen
+      if args[:in_detail] && self.split_screen
+        self.split_screen.detail_screen = screen
 
-      if args[:close_all]
+      elsif args[:in_master] && self.split_screen
+        self.split_screen.master_screen = screen 
+
+      elsif args[:close_all]
         open_root_screen screen
 
       elsif args[:modal]
@@ -25,11 +28,8 @@ module ProMotion
       elsif self.navigation_controller
         push_view_controller screen
 
-      elsif screen.respond_to?(:main_controller)
-        open_view_controller screen.main_controller
-
       else
-        open_view_controller screen
+        open_root_screen screen
 
       end
 
@@ -72,8 +72,9 @@ module ProMotion
       end
     end
 
-    def open_view_controller(vc)
-      app_delegate.load_root_view vc
+    def open_view_controller(screen)
+      PM.logger.deprecated "Use `open_root_screen` instead of the more ambiguous `open_view_controller`."
+      open_root_screen screen
     end
 
     def push_view_controller(vc, nav_controller=nil)
@@ -129,6 +130,8 @@ module ProMotion
           screen.navigation_controller = vc if screen.respond_to?("navigation_controller=")
           push_view_controller(screen, vc)
         else
+          # TODO: This should probably open the vc, shouldn't it?
+          # This isn't well tested and needs to work better.
           self.tab_bar.selectedIndex = vc.tabBarItem.tag
         end
 
diff --git a/spec/helpers/basic_screen.rb b/spec/helpers/basic_screen.rb
index cee4052..2ddfc12 100644
--- a/spec/helpers/basic_screen.rb
+++ b/spec/helpers/basic_screen.rb
@@ -1,2 +1,3 @@
 class BasicScreen < ProMotion::Screen
+  title "Basic"
 end
diff --git a/spec/helpers/detail_screen.rb b/spec/helpers/detail_screen.rb
new file mode 100644
index 0000000..000805a
--- /dev/null
+++ b/spec/helpers/detail_screen.rb
@@ -0,0 +1,3 @@
+class DetailScreen < PM::Screen
+  title "Detail"
+end
diff --git a/spec/helpers/master_screen.rb b/spec/helpers/master_screen.rb
new file mode 100644
index 0000000..46b07c7
--- /dev/null
+++ b/spec/helpers/master_screen.rb
@@ -0,0 +1,3 @@
+class MasterScreen < PM::Screen
+  title "Master"
+end
diff --git a/spec/screen_helpers_spec.rb b/spec/screen_helpers_spec.rb
index ae6c14f..d8fc089 100644
--- a/spec/screen_helpers_spec.rb
+++ b/spec/screen_helpers_spec.rb
@@ -157,20 +157,10 @@ describe "screen helpers" do
         @screen.open_screen BasicScreen
       end
 
-      it "should open the main controller if no options are provided" do
-        parent_screen = HomeScreen.new
-        nav_controller = ProMotion::NavigationController.new
-        new_screen = BasicScreen.new
-        new_screen.stub! :main_controller, return: nav_controller
-
-        parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == nav_controller  }
-        parent_screen.open_screen new_screen
-      end
-
-      it "should open the provided view controller if no other conditions are met" do
+      it "should open the provided view controller as root view if no other conditions are met" do
         parent_screen = HomeScreen.new
         new_screen = BasicScreen.new
-        parent_screen.mock!(:open_view_controller) { |vc| vc.should.be == new_screen }
+        parent_screen.mock!(:open_root_screen) { |vc| vc.should.be == new_screen }
         parent_screen.open_screen new_screen
       end
 
diff --git a/spec/screen_spec.rb b/spec/screen_spec.rb
index f493134..c2ae5ae 100644
--- a/spec/screen_spec.rb
+++ b/spec/screen_spec.rb
@@ -12,6 +12,10 @@ describe "screen properties" do
     HomeScreen.get_title.should == 'Home'
   end
 
+  it "should set title on new instances" do
+    @screen.title.should == "Home"
+  end
+
   it "should let the instance reset the title" do
     @screen.title = "instance method"
     HomeScreen.get_title.should == 'instance method'
diff --git a/spec/split_screen_spec.rb b/spec/split_screen_spec.rb
index 59744b3..83de801 100644
--- a/spec/split_screen_spec.rb
+++ b/spec/split_screen_spec.rb
@@ -3,8 +3,8 @@ describe "split screen functionality" do
   before do
     @app = TestDelegate.new
 
-    @master_screen = HomeScreen.new nav_bar: true
-    @detail_screen = BasicScreen.new # no nav_bar on this one
+    @master_screen = MasterScreen.new nav_bar: true
+    @detail_screen = DetailScreen.new # no nav_bar on this one
 
     @split_screen = @app.open_split_screen @master_screen, @detail_screen
   end
@@ -26,14 +26,42 @@ describe "split screen functionality" do
     @app.window.rootViewController.should == @split_screen
   end
 
-  it "should set the first viewController to HomeScreen" do
+  it "should set the first viewController to MasterScreen" do
     @split_screen.master_screen.should == @master_screen
     @split_screen.viewControllers.first.should == @master_screen.main_controller
   end
 
-  it "should set the second viewController to BasicScreen" do
+  it "should set the second viewController to DetailScreen" do
     @split_screen.detail_screen.should == @detail_screen
     @split_screen.viewControllers.last.should == @detail_screen.main_controller
   end
 
+  it "should set the title on both screens" do
+    @master_screen.class.send(:get_title).should == "Master"
+    @master_screen.title.should == "Master"
+    @detail_screen.class.send(:get_title).should == "Detail"
+    @detail_screen.title.should == "Detail"
+  end
 end
+
+# Regression test for https://github.com/clearsightstudio/ProMotion/issues/74
+describe "split screen with UIViewControllers with ScreenModule" do
+
+  before do
+    @app = TestDelegate.new
+
+    @master_screen = ScreenModuleViewController.new
+    @detail_screen = DetailScreen.new(nav_bar: true)
+
+    @split_screen = @app.open_split_screen @master_screen, @detail_screen
+  end
+
+  it "should set the title on both screens" do
+    @master_screen.class.send(:get_title).should == "Test Title"
+    @master_screen.title.should == "Test Title"
+    @detail_screen.class.send(:get_title).should == "Detail"
+    @detail_screen.title.should == "Detail"
+  end
+
+end
+

From d037387b4e67cf25478f8e134ab54fd7b5010e5d Mon Sep 17 00:00:00 2001
From: "Silas J. Matson" 
Date: Fri, 17 May 2013 10:33:25 -0700
Subject: [PATCH 16/18] Fix Title issue. Changed the way that screens manage
 titles.

Fixes possible conflicts in two separate instances of the same Screen.
Fixes #74
---
 lib/ProMotion/screens/_screen_module.rb       | 14 ++---
 spec/helpers/screen_module_view_controller.rb | 51 +++++++++++++++++++
 spec/screen_spec.rb                           | 11 ++--
 3 files changed, 63 insertions(+), 13 deletions(-)

diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb
index b4abe11..49cd133 100644
--- a/lib/ProMotion/screens/_screen_module.rb
+++ b/lib/ProMotion/screens/_screen_module.rb
@@ -6,13 +6,16 @@ module ProMotion
     include ProMotion::ScreenTabs
     include ProMotion::SplitScreen if NSBundle.mainBundle.infoDictionary["UIDeviceFamily"].include?("2")
 
-    attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen
+    attr_accessor :parent_screen, :first_screen, :tab_bar_item, :tab_bar, :modal, :split_screen, :title
 
     def on_create(args = {})
       unless self.is_a?(UIViewController)
         raise StandardError.new("ERROR: Screens must extend UIViewController or a subclass of UIViewController.")
       end
 
+
+      self.title = self.class.send(:get_title)
+
       args.each do |k, v|
         self.send("#{k}=", v) if self.respond_to?("#{k}=")
       end
@@ -135,15 +138,6 @@ module ProMotion
     end
     def on_disappear; end
 
-    def title
-      self.class.send(:get_title)
-    end
-
-    def title=(new_title)
-      self.class.title = new_title
-      super
-    end
-
     def main_controller
       self.navigation_controller || self
     end
diff --git a/spec/helpers/screen_module_view_controller.rb b/spec/helpers/screen_module_view_controller.rb
index 593db17..e829ea1 100644
--- a/spec/helpers/screen_module_view_controller.rb
+++ b/spec/helpers/screen_module_view_controller.rb
@@ -1,4 +1,55 @@
 class ScreenModuleViewController < UIViewController
   include PM::ScreenModule
   title 'Test Title'
+
+  # Get rid of such hackiness when RubyMotion bug is fixed...
+  
+  def self.new(args = {})
+    s = self.alloc.initWithNibName(nil, bundle:nil)
+    s.on_create(args) if s.respond_to?(:on_create)
+    s
+  end
+
+  def viewDidLoad
+    super
+    self.view_did_load if self.respond_to?(:view_did_load)
+  end
+
+  def viewWillAppear(animated)
+    super
+    self.view_will_appear(animated) if self.respond_to?("view_will_appear:")
+  end
+
+  def viewDidAppear(animated)
+    super
+    self.view_did_appear(animated) if self.respond_to?("view_did_appear:")
+  end
+
+  def viewWillDisappear(animated)
+    self.view_will_disappear(animated) if self.respond_to?("view_will_disappear:")
+    super
+  end
+
+  def viewDidDisappear(animated)
+    if self.respond_to?("view_did_disappear:")
+      self.view_did_disappear(animated)
+    end
+    super
+  end
+
+  def shouldAutorotateToInterfaceOrientation(orientation)
+    self.should_rotate(orientation)
+  end
+
+  def shouldAutorotate
+    self.should_autorotate
+  end
+
+  def willRotateToInterfaceOrientation(orientation, duration:duration)
+    self.will_rotate(orientation, duration)
+  end
+
+  def didRotateFromInterfaceOrientation(orientation)
+    self.on_rotate
+  end
 end
diff --git a/spec/screen_spec.rb b/spec/screen_spec.rb
index c2ae5ae..0326d14 100644
--- a/spec/screen_spec.rb
+++ b/spec/screen_spec.rb
@@ -12,13 +12,18 @@ describe "screen properties" do
     HomeScreen.get_title.should == 'Home'
   end
 
-  it "should set title on new instances" do
+  it "should set default title on new instances" do
     @screen.title.should == "Home"
   end
 
-  it "should let the instance reset the title" do
+  it "should let the instance set its title" do
     @screen.title = "instance method"
-    HomeScreen.get_title.should == 'instance method'
+    @screen.title.should == 'instance method'
+  end
+
+  it "should not let the instance reset the default title" do
+    @screen.title = "instance method"
+    HomeScreen.get_title.should != 'instance method'
   end
 
   it "should store debug mode" do

From 0cc70d6ebbe75fe5280e46a64bbd4ed37ec5d835 Mon Sep 17 00:00:00 2001
From: Jamon Holmgren 
Date: Fri, 17 May 2013 10:46:54 -0700
Subject: [PATCH 17/18] Version 0.6.1

---
 lib/ProMotion/version.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/ProMotion/version.rb b/lib/ProMotion/version.rb
index a198a22..0443a91 100644
--- a/lib/ProMotion/version.rb
+++ b/lib/ProMotion/version.rb
@@ -1,3 +1,3 @@
 module ProMotion
-  VERSION = "0.6.0" unless defined?(ProMotion::VERSION)
+  VERSION = "0.6.1" unless defined?(ProMotion::VERSION)
 end

From a83ec10382e97c749cbeb863413033e7141e5ff7 Mon Sep 17 00:00:00 2001
From: Tom Milewski 
Date: Sat, 18 May 2013 14:06:58 -0400
Subject: [PATCH 18/18] Allow set_nav_bar_*_button to accept UIBarButtonItem

---
 Gemfile.lock                            | 2 +-
 README.md                               | 6 ++++++
 lib/ProMotion/screens/_screen_module.rb | 2 ++
 spec/screen_helpers_spec.rb             | 9 +++++++++
 4 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/Gemfile.lock b/Gemfile.lock
index a983db2..34fecc5 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
 PATH
   remote: .
   specs:
-    ProMotion (0.6.0)
+    ProMotion (0.6.1)
 
 GEM
   remote: https://rubygems.org/
diff --git a/README.md b/README.md
index e5278d7..6faf85e 100644
--- a/README.md
+++ b/README.md
@@ -260,6 +260,12 @@ If you pass `:system` for the title, then you can get a system item. E.g.:
 set_nav_bar_right_button nil, action: :add_something, system_icon: UIBarButtonSystemItemAdd
 ```
 
+Additionally, if you pass an instance of a `UIBarButtonItem`, the `UIBarButton` will automatically display that particular button item.
+
+```ruby
+set_nav_bar_left_button self.editButtonItem
+```
+
 ## Opening and closing screens
 
 If the user taps something and you want to open a new screen, it's easy. Just use `open` and pass in the screen class
diff --git a/lib/ProMotion/screens/_screen_module.rb b/lib/ProMotion/screens/_screen_module.rb
index 49cd133..f933244 100644
--- a/lib/ProMotion/screens/_screen_module.rb
+++ b/lib/ProMotion/screens/_screen_module.rb
@@ -88,6 +88,8 @@ module ProMotion
           UIBarButtonItem.alloc.initWithImage(args[:title], style: args[:style], target: args[:target], action: args[:action])
         when Symbol, NilClass
           UIBarButtonItem.alloc.initWithBarButtonSystemItem(args[:system_icon], target: args[:target], action: args[:action]) if args[:system_icon]
+        when UIBarButtonItem
+          args[:title]
         else
           PM.logger.error("Please supply a title string, a UIImage or :system.")
       end
diff --git a/spec/screen_helpers_spec.rb b/spec/screen_helpers_spec.rb
index d8fc089..edbd290 100644
--- a/spec/screen_helpers_spec.rb
+++ b/spec/screen_helpers_spec.rb
@@ -68,6 +68,15 @@ describe "screen helpers" do
       @screen.navigationItem.leftBarButtonItem.image.should == image
     end
 
+    it "should add a left UIBarButtonItem" do
+      @screen.set_nav_bar_left_button @screen.editButtonItem
+      @screen.navigationItem.leftBarButtonItem.class.should == UIBarButtonItem
+    end
+
+    it "should add a right UIBarButtonItem" do
+      @screen.set_nav_bar_right_button @screen.editButtonItem
+      @screen.navigationItem.rightBarButtonItem.class.should == UIBarButtonItem
+    end
   end
 
   describe "screen navigation" do