menu-motion 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 934a02195b3c68b51b5bcfdf5f0907d7d3717995
4
- data.tar.gz: 5f6f318336f94e483f9cc58d2d7c17f1e42583f6
3
+ metadata.gz: 728776dec6261eb85e60dbb1d452dd1605257f62
4
+ data.tar.gz: 233be399ec008b1eb71af6146684568fc335f521
5
5
  SHA512:
6
- metadata.gz: 833c111856c289a0c5b3d977640e3d65cb92b9d02daeb6385164349b79d03582b3925b3ad1ca19888579d38039db043bd2715b6bdeefc21d46449555e5630555
7
- data.tar.gz: 815b050b4d22bbbda7601e30417897d897e75a268dd1235b03f6cde46ad4e1a773f0bfe47b5cc0088851d926fb9ee9c1d036f964c45e0fcd93b6293f2dc58adf
6
+ metadata.gz: 7f27f0192f9ef7bb1f1c2592873fa5bda6e949410b40bcc2f3d093b79bbeae54b34ce42e69c8a5a0cfe6d29e01bf7893b787e506d5d616cf00bb50d02be529ba
7
+ data.tar.gz: e57a001a46dc0fc2271f7f1b44fa541e0a247a0de2db09caf75d5891c192c2ba7ac9d37299fcd0108611a8738224dc00554b1ba444fcfd60d1ba0275f3b0b5be
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # MenuMotion
2
2
 
3
- MenuMotion is a RubyMotion wrapper inspired by Formotion for creating OS X status bar menus with a syntax that should feel familiar if you've used Formotion.
3
+ [![Build Status](https://travis-ci.org/codelation/menu-motion.svg)](https://travis-ci.org/codelation/menu-motion)
4
+ [![Code Climate](https://codeclimate.com/github/codelation/menu-motion.png)](https://codeclimate.com/github/codelation/menu-motion)
5
+
6
+ MenuMotion is a [RubyMotion](http://www.rubymotion.com) wrapper inspired by [Formotion](https://github.com/clayallsopp/formotion) for creating OS X status bar menus with a syntax that should feel familiar if you've used Formotion.
4
7
 
5
8
  ## Installation
6
9
 
@@ -67,12 +70,10 @@ menu = MenuMotion::Menu.new({
67
70
  }, {
68
71
  rows: [{
69
72
  title: "About MenuMotion",
70
- target: self,
71
- action: "about"
73
+ action: "orderFrontStandardAboutPanel:"
72
74
  }, {
73
75
  title: "Quit",
74
- target: self,
75
- action: "quit"
76
+ action: "terminate:"
76
77
  }]
77
78
  }]
78
79
  })
@@ -137,23 +138,69 @@ def action_with_sender(sender)
137
138
  end
138
139
  ```
139
140
 
141
+ ### Keyboard Shortcuts
142
+
143
+ Keyboard shortcuts can be assigned to menu items with a simple string.
144
+ The string can include multiple modifier keys, followed by the final key to be assigned (`{modifier+}{modifier+}{key}`):
145
+
146
+ ```ruby
147
+ menu = MenuMotion::Menu.new({
148
+ rows: [{
149
+ title: "Item 1",
150
+ shortcut: "command+1"
151
+ }, {
152
+ title: "Item 2",
153
+ shortcut: "control+shift+2"
154
+ }]
155
+ })
156
+ ```
157
+
158
+ #### Modifier Key Options
159
+
160
+ - **`shift`**
161
+ - **`control`**, `ctl`, `ctrl`
162
+ - **`option`**, `opt`, `alt`, `alternate`
163
+ - **`command`**, `cmd`
164
+
165
+ ### Validation
166
+
167
+ MenuMotion implements the [NSMenuValidation](https://developer.apple.com/library/mac/documentation/cocoa/reference/applicationkit/Protocols/NSMenuValidation_Protocol/Reference/Reference.html) protocol. Pass a proc to a menu item on `validate`:
168
+
169
+ ```ruby
170
+ menu = MenuMotion::Menu.new({
171
+ rows: [{
172
+ title: "Menu item",
173
+ tag: :main_item
174
+ rows: [{
175
+ title: "Submenu item 1",
176
+ tag: :submenu_item1,
177
+ target: self,
178
+ action: "do_something:",
179
+ validate: ->(menu_item) {
180
+ true # or false
181
+ }
182
+ }]
183
+ }]
184
+ })
185
+ ```
186
+
140
187
  ### Updating Menu Items
141
188
 
142
- Assign keys to menu items that will need to be updated.
189
+ Assign tags to menu items that will need to be updated.
143
190
 
144
191
  ```ruby
145
192
  menu = MenuMotion::Menu.new({
146
193
  rows: [{
147
194
  title: "Menu item",
148
- key: :main_item
195
+ tag: :main_item
149
196
  rows: [{
150
197
  title: "Submenu item 1",
151
- key: :submenu_item1,
198
+ tag: :submenu_item1,
152
199
  target: self,
153
200
  action: "do_something:"
154
201
  }, {
155
202
  title: "Submenu item 2",
156
- key: :submenu_item2,
203
+ tag: :submenu_item2,
157
204
  target: self,
158
205
  action: "do_something:"
159
206
  }]
@@ -161,13 +208,13 @@ menu = MenuMotion::Menu.new({
161
208
  })
162
209
 
163
210
  # Let's update the first item's title:
164
- menu.update(:main_item, {
211
+ menu.update_item_with_tag(:main_item, {
165
212
  title: "Hello World"
166
213
  })
167
214
 
168
215
  # And give the first submenu item a submenu.
169
216
  # The target and action will not be used if a submenu is defined.
170
- menu.update(:submenu_item1, {
217
+ menu.update_item_with_tag(:submenu_item1, {
171
218
  rows: [{
172
219
  title: "Click me",
173
220
  target: self,
@@ -176,6 +223,11 @@ menu.update(:submenu_item1, {
176
223
  })
177
224
  ```
178
225
 
226
+ ## TODO
227
+
228
+ - Menu Item Icons
229
+ - Keyboard Shortcuts
230
+
179
231
  ## Contributing
180
232
 
181
233
  1. Fork it
@@ -2,34 +2,25 @@ module MenuMotion
2
2
 
3
3
  class Menu < NSMenu
4
4
 
5
- attr_accessor :menu_items
6
- attr_accessor :root_menu
5
+ attr_accessor :menu_items, :root_menu
7
6
 
8
7
  def add_rows_to_menu(menu, rows)
9
8
  rows.each do |row|
10
- menu_item = NSMenuItem.alloc.initWithTitle(row[:title], action: row[:action], keyEquivalent:"")
11
- menu_item.target = row[:target]
12
-
13
- # Add sections and/or rows to a submenu
14
- if row[:sections]
15
- submenu = MenuMotion::Menu.new({
16
- sections: row[:sections]
17
- }, self.root_menu || self)
18
- menu_item.setSubmenu(submenu)
19
- elsif row[:rows]
20
- submenu = MenuMotion::Menu.new({
21
- rows: row[:rows]
22
- }, self.root_menu || self)
23
- menu_item.setSubmenu(submenu)
24
- end
9
+ row[:root_menu] = WeakRef.new(self.root_menu || self)
10
+ menu_item = MenuMotion::MenuItem.new(row)
11
+ menu_item.target = self
12
+ menu_item.action = "perform_action:"
13
+
14
+ if tag = row[:tag]
15
+ tag = tag.to_sym
16
+ menu_item.tag = tag
25
17
 
26
- if row[:key]
27
18
  if self.root_menu
28
19
  self.root_menu.menu_items ||= {}
29
- self.root_menu.menu_items[row[:key].to_sym] = WeakRef.new(menu_item)
20
+ self.root_menu.menu_items[tag] = WeakRef.new(menu_item)
30
21
  else
31
22
  self.menu_items ||= {}
32
- self.menu_items[row[:key].to_sym] = WeakRef.new(menu_item)
23
+ self.menu_items[tag] = WeakRef.new(menu_item)
33
24
  end
34
25
  end
35
26
 
@@ -59,7 +50,11 @@ module MenuMotion
59
50
  end
60
51
 
61
52
  def initialize(params = {}, root_menu = nil)
62
- super()
53
+ if params[:title]
54
+ initWithTitle(params[:title])
55
+ else
56
+ super()
57
+ end
63
58
 
64
59
  self.root_menu = root_menu
65
60
  self.build_menu_from_params(self, params)
@@ -67,22 +62,24 @@ module MenuMotion
67
62
  self
68
63
  end
69
64
 
70
- def item_with_key(key)
65
+ def item_with_tag(tag)
71
66
  @menu_items ||= {}
72
- @menu_items[key.to_sym]
67
+ @menu_items[tag.to_sym]
73
68
  end
74
69
 
75
- def update(key, params)
76
- menu_item = self.item_with_key(key)
70
+ def perform_action(menu_item)
71
+ menu_item.perform_action
72
+ end
77
73
 
78
- menu_item.title = params[:title] if params[:title]
79
- menu_item.target = params[:target] if params[:target]
80
- menu_item.action = params[:action] if params[:action]
74
+ def update_item_with_tag(tag, params)
75
+ menu_item = self.item_with_tag(tag)
76
+ menu_item.update(params)
77
+ end
81
78
 
82
- self
79
+ def validateMenuItem(menu_item)
80
+ menu_item.valid?
83
81
  end
84
82
 
85
83
  end
86
84
 
87
85
  end
88
-
@@ -0,0 +1,106 @@
1
+ module MenuMotion
2
+
3
+ class MenuItem < NSMenuItem
4
+
5
+ attr_accessor :item_action, :item_target,
6
+ :root_menu, :tag, :validate
7
+
8
+ def initialize(params = {})
9
+ super()
10
+ update(params)
11
+ self
12
+ end
13
+
14
+ def perform_action
15
+ if self.valid? && self.valid_target_and_action?
16
+ if self.item_action.to_s.end_with?(":")
17
+ self.item_target.performSelector(self.item_action, withObject: self)
18
+ else
19
+ self.item_target.performSelector(self.item_action)
20
+ end
21
+ end
22
+ end
23
+
24
+ def update(params)
25
+ self.item_action = params[:action] if params.has_key?(:action)
26
+ self.item_target = params[:target] if params.has_key?(:target)
27
+ self.root_menu = params[:root_menu] if params.has_key?(:root_menu)
28
+ self.title = params[:title] if params.has_key?(:title)
29
+ self.validate = params[:validate] if params.has_key?(:validate)
30
+
31
+ # Set NSApp as the default target if no other target is given
32
+ if self.item_action && self.item_target.nil?
33
+ self.item_target = NSApp
34
+ end
35
+
36
+ # Setup submenu and keyboard shortcut
37
+ set_submenu_from_params(params)
38
+ set_keyboard_shortcut(params[:shortcut]) if params.has_key?(:shortcut)
39
+
40
+ self
41
+ end
42
+
43
+ def valid?
44
+ if self.submenu || self.valid_target_and_action?
45
+ if self.validate.nil?
46
+ true
47
+ else
48
+ self.validate.call(self)
49
+ end
50
+ else
51
+ false
52
+ end
53
+ end
54
+
55
+ def valid_target_and_action?
56
+ self.item_target && self.item_action && self.item_target.respond_to?(self.item_action.gsub(":", ""))
57
+ end
58
+
59
+ private
60
+
61
+ def set_keyboard_shortcut(shortcut)
62
+ if shortcut
63
+ keys = shortcut.gsub("-", "+").split("+")
64
+ key = keys.pop
65
+ modifier_mask = 0
66
+ modifier_keys = keys
67
+
68
+ modifier_keys.each do |modifier_key|
69
+ case modifier_key
70
+ when "alt", "alternate", "opt", "option"
71
+ modifier_mask |= NSAlternateKeyMask
72
+ when "cmd", "command"
73
+ modifier_mask |= NSCommandKeyMask
74
+ when "ctl", "ctrl", "control"
75
+ modifier_mask |= NSControlKeyMask
76
+ when "shift"
77
+ modifier_mask |= NSShiftKeyMask
78
+ end
79
+ end
80
+
81
+ self.setKeyEquivalent(key)
82
+ self.setKeyEquivalentModifierMask(modifier_mask)
83
+ else
84
+ self.setKeyEquivalent(nil)
85
+ self.setKeyEquivalentModifierMask(nil)
86
+ end
87
+ end
88
+
89
+ def set_submenu_from_params(params)
90
+ if params[:sections]
91
+ submenu = MenuMotion::Menu.new({
92
+ sections: params[:sections]
93
+ }, self.root_menu)
94
+ self.setSubmenu(submenu)
95
+ elsif params[:rows]
96
+ submenu = MenuMotion::Menu.new({
97
+ rows: params[:rows]
98
+ }, self.root_menu)
99
+ self.setSubmenu(submenu)
100
+ end
101
+ end
102
+
103
+ end
104
+
105
+ end
106
+
@@ -1,3 +1,3 @@
1
1
  module MenuMotion
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: menu-motion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Pattison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-18 00:00:00.000000000 Z
11
+ date: 2014-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -35,6 +35,7 @@ files:
35
35
  - README.md
36
36
  - lib/menu_motion.rb
37
37
  - lib/menu_motion/menu.rb
38
+ - lib/menu_motion/menu_item.rb
38
39
  - lib/menu_motion/version.rb
39
40
  homepage: https://github.com/codelation/menu-motion
40
41
  licenses: