everyday-menu 0.4.0 → 1.0.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: 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