everyday-menu 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4519240679e0389183ed2e8dba773a4ed67c970a
4
- data.tar.gz: 9ed56ec79c9022bc2bdeff2f6603363567b3f17b
3
+ metadata.gz: e245af3b08954f17c48965a894d13e01b8335649
4
+ data.tar.gz: 0ce77623e08bed86d0329e5e0d9a196e5261e7fe
5
5
  SHA512:
6
- metadata.gz: 96ac26b404b7f1bcd0dc78fa3118041e77fdb995084961e0c1e877b8f72fe76c1f86e3419438ae83ee930b30445bdec8e74c919ca8d8fbd8f7c755749a9daf8e
7
- data.tar.gz: 7a4ce75150edbe04fb1b8cb7ea985459265625a31e2d17ab5317cd81fdd159a79b42ed151a4cd52eaca07356f3affd5515109d7cbc17f606ce772d98f6a5b9c1
6
+ metadata.gz: 781454de5673aabd1a39be97feae58cb19dc1f2fd7fb21ac67e55ed0d12eadd3a8f7eb54a8f2145d34a0aac51a7c5d8c2b53a971124879f7a6a890e1fb837d59
7
+ data.tar.gz: 8ee6356acd25e9ecc634fd900dc133f7a01c98a59e328c631aa1e928d6a5fdecb9fae745d126a2ca9ddc8c6a364ceb268b8ee2c68816b86170e9b91861767c7b
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # EverydayMenu
2
2
 
3
3
  ## Updates
4
- Please see the "Introducing Presets!" section below for an awesome new feature!
4
+ * Please see the "Introducing Presets!" section below for an awesome new feature!
5
+ * Please see the "Introducing Statusbar Menus!" section below for another awesome new feature!
5
6
 
6
7
  ## Issue Tracking
7
8
  Please use <https://everydayprogramminggenius.atlassian.net/browse/EM> for issue tracking.
@@ -177,6 +178,35 @@ EverydayMenu::MenuItem.definePreset(:services) { |item|
177
178
 
178
179
  Any block you pass to `item.registerOnBuild(&block)` will be added to a list of blocks to be run when the menu setup is built.
179
180
 
181
+ ## Introducing Statusbar Menus!
182
+ As of version 1.0.0, `everyday-menu` now supports creating statusbar menus. With this addition, I believe I have finally matched all of the important features of `drink-menu`.
183
+
184
+ Here's how you can make a menu be for the statusbar icon:
185
+
186
+ ```ruby
187
+ class MainMenu
188
+ extend EverydayMenu::MenuBuilder
189
+
190
+ menuItem :status_open, 'Open', key_equivalent: 'o'
191
+ menuItem :status_new, 'New'
192
+ menuItem :status_close, 'Close', key_equivalent: 'w'
193
+ menuItem :status_quit, 'Quit', preset: :quit
194
+
195
+ statusbarMenu(:statusbar, 'Statusbar Menu', status_item_icon: 'icon', status_item_view_class: ViewClass) {
196
+ status_new
197
+ status_open
198
+ ___
199
+ status_close
200
+ ___
201
+ status_quit
202
+ }
203
+ end
204
+ ```
205
+
206
+ This will create a statusbar menu with the specified title, icon, and view class.
207
+
208
+ You can also create a statusbar menu by using the key `status_item_title:`, `status_item_icon:`, and/or `status_item_view_class:` in a regular (non-main) menu. Other than the addition of these parameters, a statusbar menu has all of the same parameters as a regular menu.
209
+
180
210
 
181
211
  ## Known Issues
182
212
 
@@ -15,5 +15,17 @@ class AppDelegate
15
15
  @has_open = true
16
16
  puts 'open'
17
17
  }
18
+ MainMenu[:statusbar].subscribe(:status_new) { |_, _|
19
+ @has_open = true
20
+ puts 'status-new'
21
+ }
22
+ MainMenu[:statusbar].subscribe(:status_close) { |_, _|
23
+ @has_open = false
24
+ puts 'status-close'
25
+ }.canExecuteBlock { |_| @has_open }
26
+ MainMenu[:statusbar].subscribe(:status_open) { |_, _|
27
+ @has_open = true
28
+ puts 'status-open'
29
+ }
18
30
  end
19
31
  end
@@ -11,6 +11,12 @@ class MainMenu
11
11
  menuItem :new, 'New'
12
12
  menuItem :close, 'Close', key_equivalent: 'w'
13
13
 
14
+ menuItem :status_open, 'Open', key_equivalent: 'o'
15
+ menuItem :status_new, 'New'
16
+ menuItem :status_close, 'Close', key_equivalent: 'w'
17
+ menuItem :status_quit, 'Quit', preset: :quit
18
+
19
+
14
20
  mainMenu(:app, 'Blah') {
15
21
  hide_others
16
22
  show_all
@@ -26,4 +32,13 @@ class MainMenu
26
32
  ___
27
33
  close
28
34
  }
35
+
36
+ statusbarMenu(:statusbar, 'Statusbar Menu') {
37
+ status_new
38
+ status_open
39
+ ___
40
+ status_close
41
+ ___
42
+ status_quit
43
+ }
29
44
  end
@@ -1,6 +1,16 @@
1
1
  module EverydayMenu
2
2
  class Menu
3
- attr_reader :needsMenuItem
3
+ include MyAccessors
4
+
5
+ my_attr_writer :label
6
+
7
+ my_attr_accessor_bool :servicesMenu, :windowsMenu, :helpMenu, :mainMenu
8
+
9
+ my_attr_reader_bool :statusMenu
10
+
11
+ my_attr_reader :statusItemTitle, :statusItemIcon, :statusItemViewClass
12
+
13
+ attr_reader :menu, :builder
4
14
 
5
15
  def self.create(label, title, options = {}, &block)
6
16
  new(label, &block).tap { |menu|
@@ -11,14 +21,18 @@ module EverydayMenu
11
21
  end
12
22
 
13
23
  def initialize(label, &block)
14
- @label = label
15
- @builder = block
16
- @menu = NSMenu.alloc.init
17
- @menuItems = MenuItemList.new(@menu)
18
- @needsMenuItem = false
19
- @servicesMenu = false
20
- @windowMenu = false
21
- @helpMenu = false
24
+ @label = label
25
+ @builder = block
26
+ @menu = NSMenu.alloc.init
27
+ @menuItems = MenuItemList.new(@menu)
28
+ @mainMenu = false
29
+ @statusMenu = false
30
+ @servicesMenu = false
31
+ @windowsMenu = false
32
+ @helpMenu = false
33
+ @statusItemTitle = nil
34
+ @statusItemIcon = nil
35
+ @statusItemViewClass = nil
22
36
  end
23
37
 
24
38
  def menuItemFromMenu!
@@ -42,136 +56,79 @@ module EverydayMenu
42
56
  @menuItems << item
43
57
  end
44
58
 
45
- def has(key)
46
- name = key_to_name(key, 'has')
47
- if self.respond_to?(name)
48
- self.send(name)
49
- else
50
- @menu.send(name)
51
- end
52
- end
53
-
54
- def is(key)
55
- name = key_to_name(key, 'is')
56
- if self.respond_to?(name)
57
- self.send(name)
58
- else
59
- @menu.send(name)
60
- end
61
- end
62
-
63
- def [](key)
64
- name = key_to_name(key)
65
- if self.respond_to?(name)
66
- self.send(name)
67
- else
68
- @menu.send(name)
69
- end
59
+ def containedObject
60
+ @menu
70
61
  end
71
62
 
72
- def []=(key, value)
73
- name = key_to_name(key, 'set')
74
- if self.respond_to?(name)
75
- self.send(name, value)
76
- else
77
- @menu.send(name, value)
78
- end
63
+ def runOnBuild
64
+ @@buildBlocks ||= {}
65
+ @@buildBlocks.each { |block| block[1].call(self) if self.is(block[0]) }
66
+ @menuItems.each { |item| item.runOnBuild }
79
67
  end
80
68
 
81
- def key_to_name(key, prefix = nil)
82
- rval = key.to_s.gsub(/_(\w)/) { |_| $1.upcase }
83
- prefix.nil? ? rval : "#{prefix}#{rval[0].upcase}#{rval[1..-1]}"
69
+ def self.registerBuildBlock(field, &block)
70
+ @@buildBlocks ||= {}
71
+ @@buildBlocks[field] = block
84
72
  end
85
73
 
86
- def runOnBuild
87
- if self.is :services_menu
88
- NSApp.servicesMenu = self.menu
89
- end
90
- if self.is :windows_menu
91
- NSApp.windowsMenu = self.menu
92
- end
93
- if self.is :help_menu
94
- NSApp.helpMenu = self.menu
95
- end
96
- @menuItems.each { |item| item.runOnBuild }
97
- end
74
+ registerBuildBlock(:services_menu) { |menu| NSApp.servicesMenu = menu.menu }
75
+ registerBuildBlock(:windows_menu) { |menu| NSApp.windowsMenu = menu.menu }
76
+ registerBuildBlock(:help_menu) { |menu| NSApp.helpMenu = menu.menu }
77
+ registerBuildBlock(:status_menu) { |menu| menu.createStatusItem! }
98
78
 
99
79
  def label
100
80
  @label ||= nil
101
81
  end
102
82
 
103
- def setLabel(label)
104
- @label = label
105
- end
106
-
107
- alias :label= :setLabel
108
-
109
- def isServicesMenu
110
- @servicesMenu
83
+ def setStatusItemTitle(title)
84
+ @mainMenu = false unless title.nil?
85
+ @statusItemTitle = title
86
+ @statusMenu = true unless title.nil?
111
87
  end
112
88
 
113
- alias :servicesMenu :isServicesMenu
114
- alias :services_menu? :isServicesMenu
89
+ alias :statusItemTitle= :setStatusItemTitle
90
+ alias :status_item_title= :setStatusItemTitle
115
91
 
116
- def setServicesMenu(value)
117
- @servicesMenu = value
92
+ def setStatusItemIcon(icon)
93
+ @mainMenu = false unless icon.nil?
94
+ @statusItemIcon = icon
95
+ @statusMenu = true unless icon.nil?
118
96
  end
119
97
 
120
- alias :servicesMenu= :setServicesMenu
121
- alias :services_menu= :setServicesMenu
98
+ alias :statusItemIcon= :setStatusItemIcon
99
+ alias :status_item_icon= :setStatusItemIcon
122
100
 
123
- def isWindowsMenu
124
- @windowMenu
101
+ def setStatusItemViewClass(viewClass)
102
+ @mainMenu = false unless viewClass.nil?
103
+ @statusItemViewClass = viewClass
104
+ @statusMenu = true unless viewClass.nil?
125
105
  end
126
106
 
127
- alias :windowsMenu :isWindowsMenu
128
- alias :windows_menu? :isWindowsMenu
107
+ alias :statusItemViewClass= :setStatusItemViewClass
108
+ alias :status_item_view_class= :setStatusItemViewClass
129
109
 
130
- def setWindowsMenu(value)
131
- @windowMenu = value
132
- end
110
+ def createStatusItem!
111
+ statusBar = NSStatusBar.systemStatusBar
112
+ @statusItem = statusBar.statusItemWithLength(NSSquareStatusItemLength)
113
+ @statusItem.highlightMode = true
133
114
 
134
- alias :windowsMenu= :setWindowsMenu
135
- alias :windows_menu= :setWindowsMenu
115
+ @statusItem.menu = self.menu
136
116
 
137
- def isHelpMenu
138
- @helpMenu
139
- end
117
+ unless @statusItemViewClass.nil?
118
+ statusItemView = @statusItemViewClass.viewWithStatusItem(@statusItem)
119
+ @statusItem.menu.delegate = @statusItemView
120
+ @statusItem.view = statusItemView
121
+ end
140
122
 
141
- alias :helpMenu :isHelpMenu
142
- alias :help_menu? :isHelpMenu
123
+ @statusItem.title = @statusItemTitle
124
+ @statusItem.image = @statusItemIcon
143
125
 
144
- def setHelpMenu(value)
145
- @helpMenu = value
126
+ @statusItem
146
127
  end
147
128
 
148
- alias :helpMenu= :setHelpMenu
149
- alias :help_menu= :setHelpMenu
150
-
151
129
  def items
152
130
  @menuItems
153
131
  end
154
-
155
- def menu
156
- @menu
157
- end
158
-
159
- def builder
160
- @builder
161
- end
162
-
163
- def isMainMenu
164
- @needsMenuItem
165
- end
166
-
167
- alias :mainMenu :isMainMenu
168
- alias :main_menu? :isMainMenu
169
-
170
- def setMainMenu(value)
171
- @needsMenuItem = value
172
- end
173
-
174
- alias :main_menu= :setMainMenu
175
132
  end
176
133
 
177
134
  class MenuItemList
@@ -45,6 +45,13 @@ module EverydayMenu
45
45
  @menus[label] = Menu.create(label, title, options, &block)
46
46
  end
47
47
 
48
+ def statusbarMenu(label, title, options = {}, &block)
49
+ options[:main_menu] = false
50
+ options[:status_item_title] = title unless options.has_key?(:status_item_title)
51
+ @menus ||= {}
52
+ @menus[label] = Menu.create(label, title, options, &block)
53
+ end
54
+
48
55
  def [](label)
49
56
  @menus[label]
50
57
  end
@@ -1,5 +1,7 @@
1
1
  module EverydayMenu
2
2
  class MenuItem
3
+ include MyAccessors
4
+
3
5
  def self.create(label, title, options = {})
4
6
  new.tap { |item|
5
7
  item[:label] = label
@@ -25,67 +27,22 @@ module EverydayMenu
25
27
  @menuItem = menuItem || NSMenuItem.alloc.init
26
28
  end
27
29
 
28
- def has(key)
29
- name = key_to_name(key, 'has')
30
- if self.respond_to?(name)
31
- self.send(name)
32
- else
33
- @menuItem.send(name)
34
- end
35
- end
36
-
37
- def is(key)
38
- name = key_to_name(key, 'is')
39
- if self.respond_to?(name)
40
- self.send(name)
41
- else
42
- @menuItem.send(name)
43
- end
44
- end
45
-
46
- def [](key)
47
- name = key_to_name(key)
48
- if self.respond_to?(name)
49
- self.send(name)
50
- else
51
- @menuItem.send(name)
52
- end
53
- end
54
-
55
- def []=(key, value)
56
- name = key_to_name(key, 'set')
57
- if self.respond_to?(name)
58
- self.send(name, value)
59
- else
60
- @menuItem.send(name, value)
61
- end
62
- end
63
-
64
- def key_to_name(key, prefix = nil)
65
- rval = key.to_s.gsub(/_(\w)/) { |_| $1.upcase }
66
- prefix.nil? ? rval : "#{prefix}#{rval[0].upcase}#{rval[1..-1]}"
30
+ def containedObject
31
+ @menuItem
67
32
  end
68
33
 
69
34
  def setSubmenu(menu)
70
35
  @menuItem.submenu = menu.menu
71
36
  end
72
37
 
73
- def menuItem
74
- @menuItem
75
- end
76
-
77
- alias :menu_item :menuItem
38
+ my_attr_reader :menuItem
78
39
  alias :item :menuItem
79
40
 
80
41
  def label
81
42
  @label ||= nil
82
43
  end
83
44
 
84
- def setLabel(label)
85
- @label = label
86
- end
87
-
88
- alias :label= :setLabel
45
+ my_attr_writer :label
89
46
 
90
47
  def tag
91
48
  @menuItem.tag
@@ -0,0 +1,160 @@
1
+ module EverydayMenu
2
+ class EverydayCommand
3
+ attr_reader :label
4
+ attr_writer :canExecute
5
+
6
+ def initialize(label, canExecute = true, &block)
7
+ @label = label
8
+ @block = block
9
+ @canExecute = canExecute
10
+ @canExecuteBlock = nil
11
+ end
12
+
13
+ def canExecuteBlock(&block)
14
+ @canExecuteBlock = block
15
+ end
16
+
17
+ def canExecute
18
+ @canExecuteBlock.nil? ? @canExecute : @canExecuteBlock.call(self)
19
+ end
20
+
21
+ def execute(sender)
22
+ @block.call(self, sender)
23
+ end
24
+ end
25
+
26
+ class CommandList
27
+ attr_accessor :label
28
+
29
+ def initialize(label)
30
+ @label = label
31
+ @items = []
32
+ end
33
+
34
+ def add(&block)
35
+ @items << EverydayCommand.new(@label, &block)
36
+ end
37
+
38
+ def last
39
+ @items.last
40
+ end
41
+
42
+ def execute(sender)
43
+ @items.each { |item| item.execute(sender) }
44
+ end
45
+
46
+ def canExecute
47
+ @items.any? { |item| item.canExecute }
48
+ end
49
+ end
50
+
51
+ module MyAccessors
52
+ def has(key)
53
+ name = self.class.key_to_name(key, 'has')
54
+ if self.respond_to?(name)
55
+ self.send(name)
56
+ else
57
+ self.containedObject.send(name)
58
+ end
59
+ end
60
+
61
+ def is(key)
62
+ name = self.class.key_to_name(key, 'is')
63
+ if self.respond_to?(name)
64
+ self.send(name)
65
+ else
66
+ self.containedObject.send(name)
67
+ end
68
+ end
69
+
70
+ def [](key)
71
+ name = self.class.key_to_name(key)
72
+ if self.respond_to?(name)
73
+ self.send(name)
74
+ else
75
+ self.containedObject.send(name)
76
+ end
77
+ end
78
+
79
+ def []=(key, value)
80
+ name = self.class.key_to_name(key, 'set')
81
+ if self.respond_to?(name)
82
+ self.send(name, value)
83
+ else
84
+ self.containedObject.send(name, value)
85
+ end
86
+ end
87
+
88
+ class << self
89
+ def self.key_to_name(key, prefix = nil)
90
+ rval = key.to_s.gsub(/_(\w)/) { |_| $1.upcase }
91
+ prefix.nil? ? rval : "#{prefix}#{rval[0].upcase}#{rval[1..-1]}"
92
+ end
93
+
94
+ def self.name_to_key(name)
95
+ name.to_s.gsub(/A-Z/) { |c| c.downcase }.to_sym
96
+ end
97
+
98
+ def self.my_attr_accessor(*names)
99
+ names.each { |name|
100
+ var_name = :"@#{name.to_s}"
101
+ define_method(name) { self.instance_variable_get(var_name) }
102
+ define_method(:"#{name.to_s}=") { |val| self.instance_variable_set(var_name, val) }
103
+ setName = :"set#{name.to_s[0].upcase}#{name.to_s[1..-1]}"
104
+ define_method(setName) { |val| self.instance_variable_set(var_name, val) }
105
+ name2 = name_to_key(name)
106
+ define_method(name2) { self.instance_variable_get(var_name) }
107
+ define_method(:"#{name2.to_s}=") { |val| self.instance_variable_set(var_name, val) }
108
+ }
109
+ end
110
+
111
+ def self.my_attr_accessor_bool(*names)
112
+ names.each { |name|
113
+ var_name = :"@#{name.to_s}"
114
+ define_method(name) { self.instance_variable_get(var_name) }
115
+ define_method(:"#{name.to_s}=") { |val| self.instance_variable_set(var_name, val) }
116
+ isName = :"#{key_to_name(name, 'is')}"
117
+ define_method(isName) { self.instance_variable_get(var_name) }
118
+ setName = :"#{key_to_name(name, 'set')}"
119
+ define_method(setName) { |val| self.instance_variable_set(var_name, val) }
120
+ name2 = name_to_key(name)
121
+ define_method(name2) { self.instance_variable_get(var_name) }
122
+ define_method(:"#{name2.to_s}?") { self.instance_variable_get(var_name) }
123
+ define_method(:"#{name2.to_s}=") { |val| self.instance_variable_set(var_name, val) }
124
+ }
125
+ end
126
+
127
+ def self.my_attr_reader(*names)
128
+ names.each { |name|
129
+ var_name = :"@#{name.to_s}"
130
+ define_method(name) { self.instance_variable_get(var_name) }
131
+ name2 = name_to_key(name)
132
+ define_method(name2) { self.instance_variable_get(var_name) }
133
+ }
134
+ end
135
+
136
+ def self.my_attr_reader_bool(*names)
137
+ names.each { |name|
138
+ var_name = :"@#{name.to_s}"
139
+ define_method(name) { self.instance_variable_get(var_name) }
140
+ isName = :"#{key_to_name(name, 'is')}"
141
+ define_method(isName) { self.instance_variable_get(var_name) }
142
+ name2 = name_to_key(name)
143
+ define_method(name2) { self.instance_variable_get(var_name) }
144
+ define_method(:"#{name2.to_s}?") { self.instance_variable_get(var_name) }
145
+ }
146
+ end
147
+
148
+ def self.my_attr_writer(*names)
149
+ names.each { |name|
150
+ var_name = :"@#{name.to_s}"
151
+ define_method(:"#{name.to_s}=") { |val| self.instance_variable_set(var_name, val) }
152
+ setName = :"#{key_to_name(name, 'set')}"
153
+ define_method(setName) { |val| self.instance_variable_set(var_name, val) }
154
+ name2 = name_to_key(name)
155
+ define_method(:"#{name2.to_s}=") { |val| self.instance_variable_set(var_name, val) }
156
+ }
157
+ end
158
+ end
159
+ end
160
+ end
@@ -1,3 +1,3 @@
1
1
  module EverydayMenu
2
- VERSION = '0.4.0'
2
+ VERSION = '1.0.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: everyday-menu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Henderson
@@ -55,10 +55,10 @@ files:
55
55
  - examples/basic_main_menu/app_delegate.rb
56
56
  - examples/basic_main_menu/main_menu.rb
57
57
  - lib/everyday-menu.rb
58
- - lib/everyday-menu/everyday_command.rb
59
58
  - lib/everyday-menu/menu.rb
60
59
  - lib/everyday-menu/menu_builder.rb
61
60
  - lib/everyday-menu/menu_item.rb
61
+ - lib/everyday-menu/utils.rb
62
62
  - lib/everyday-menu/version.rb
63
63
  - spec/menu_builder_spec.rb
64
64
  - spec/menu_item_spec.rb
@@ -1,50 +0,0 @@
1
- module EverydayMenu
2
- class EverydayCommand
3
- attr_reader :label
4
- attr_writer :canExecute
5
-
6
- def initialize(label, canExecute = true, &block)
7
- @label = label
8
- @block = block
9
- @canExecute = canExecute
10
- @canExecuteBlock = nil
11
- end
12
-
13
- def canExecuteBlock(&block)
14
- @canExecuteBlock = block
15
- end
16
-
17
- def canExecute
18
- @canExecuteBlock.nil? ? @canExecute : @canExecuteBlock.call(self)
19
- end
20
-
21
- def execute(sender)
22
- @block.call(self, sender)
23
- end
24
- end
25
-
26
- class CommandList
27
- attr_accessor :label
28
-
29
- def initialize(label)
30
- @label = label
31
- @items = []
32
- end
33
-
34
- def add(&block)
35
- @items << EverydayCommand.new(@label, &block)
36
- end
37
-
38
- def last
39
- @items.last
40
- end
41
-
42
- def execute(sender)
43
- @items.each { |item| item.execute(sender) }
44
- end
45
-
46
- def canExecute
47
- @items.any? { |item| item.canExecute }
48
- end
49
- end
50
- end