hotcocoa 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/bin/hotcocoa +31 -0
- data/lib/hotcocoa/application_builder.rb +320 -0
- data/lib/hotcocoa/attributed_string.rb +143 -0
- data/lib/hotcocoa/behaviors.rb +7 -0
- data/lib/hotcocoa/data_sources/combo_box_data_source.rb +44 -0
- data/lib/hotcocoa/data_sources/table_data_source.rb +18 -0
- data/lib/hotcocoa/delegate_builder.rb +85 -0
- data/lib/hotcocoa/graphics/canvas.rb +836 -0
- data/lib/hotcocoa/graphics/color.rb +781 -0
- data/lib/hotcocoa/graphics/elements/particle.rb +75 -0
- data/lib/hotcocoa/graphics/elements/rope.rb +99 -0
- data/lib/hotcocoa/graphics/elements/sandpainter.rb +71 -0
- data/lib/hotcocoa/graphics/gradient.rb +63 -0
- data/lib/hotcocoa/graphics/image.rb +488 -0
- data/lib/hotcocoa/graphics/path.rb +325 -0
- data/lib/hotcocoa/graphics/pdf.rb +71 -0
- data/lib/hotcocoa/graphics.rb +161 -0
- data/lib/hotcocoa/kernel_ext.rb +14 -0
- data/lib/hotcocoa/kvo_accessors.rb +48 -0
- data/lib/hotcocoa/layout_view.rb +448 -0
- data/lib/hotcocoa/mapper.rb +227 -0
- data/lib/hotcocoa/mapping_methods.rb +40 -0
- data/lib/hotcocoa/mappings/alert.rb +25 -0
- data/lib/hotcocoa/mappings/application.rb +112 -0
- data/lib/hotcocoa/mappings/array_controller.rb +87 -0
- data/lib/hotcocoa/mappings/box.rb +39 -0
- data/lib/hotcocoa/mappings/button.rb +92 -0
- data/lib/hotcocoa/mappings/collection_view.rb +44 -0
- data/lib/hotcocoa/mappings/color.rb +28 -0
- data/lib/hotcocoa/mappings/column.rb +21 -0
- data/lib/hotcocoa/mappings/combo_box.rb +24 -0
- data/lib/hotcocoa/mappings/control.rb +33 -0
- data/lib/hotcocoa/mappings/font.rb +44 -0
- data/lib/hotcocoa/mappings/gradient.rb +15 -0
- data/lib/hotcocoa/mappings/image.rb +15 -0
- data/lib/hotcocoa/mappings/image_view.rb +43 -0
- data/lib/hotcocoa/mappings/label.rb +25 -0
- data/lib/hotcocoa/mappings/layout_view.rb +9 -0
- data/lib/hotcocoa/mappings/menu.rb +71 -0
- data/lib/hotcocoa/mappings/menu_item.rb +47 -0
- data/lib/hotcocoa/mappings/movie.rb +13 -0
- data/lib/hotcocoa/mappings/movie_view.rb +27 -0
- data/lib/hotcocoa/mappings/notification.rb +17 -0
- data/lib/hotcocoa/mappings/popup.rb +110 -0
- data/lib/hotcocoa/mappings/progress_indicator.rb +68 -0
- data/lib/hotcocoa/mappings/scroll_view.rb +29 -0
- data/lib/hotcocoa/mappings/search_field.rb +9 -0
- data/lib/hotcocoa/mappings/secure_text_field.rb +17 -0
- data/lib/hotcocoa/mappings/segmented_control.rb +97 -0
- data/lib/hotcocoa/mappings/slider.rb +25 -0
- data/lib/hotcocoa/mappings/sort_descriptor.rb +13 -0
- data/lib/hotcocoa/mappings/sound.rb +9 -0
- data/lib/hotcocoa/mappings/speech_synthesizer.rb +25 -0
- data/lib/hotcocoa/mappings/split_view.rb +21 -0
- data/lib/hotcocoa/mappings/status_bar.rb +7 -0
- data/lib/hotcocoa/mappings/status_item.rb +9 -0
- data/lib/hotcocoa/mappings/table_view.rb +110 -0
- data/lib/hotcocoa/mappings/text_field.rb +41 -0
- data/lib/hotcocoa/mappings/text_view.rb +13 -0
- data/lib/hotcocoa/mappings/timer.rb +25 -0
- data/lib/hotcocoa/mappings/toolbar.rb +97 -0
- data/lib/hotcocoa/mappings/toolbar_item.rb +36 -0
- data/lib/hotcocoa/mappings/view.rb +67 -0
- data/lib/hotcocoa/mappings/web_view.rb +22 -0
- data/lib/hotcocoa/mappings/window.rb +118 -0
- data/lib/hotcocoa/mappings/xml_parser.rb +41 -0
- data/lib/hotcocoa/mappings.rb +109 -0
- data/lib/hotcocoa/mvc.rb +175 -0
- data/lib/hotcocoa/notification_listener.rb +62 -0
- data/lib/hotcocoa/object_ext.rb +22 -0
- data/lib/hotcocoa/plist.rb +45 -0
- data/lib/hotcocoa/standard_rake_tasks.rb +17 -0
- data/lib/hotcocoa/template.rb +27 -0
- data/lib/hotcocoa/virtual_file_system.rb +172 -0
- data/lib/hotcocoa.rb +26 -0
- data/template/Rakefile +5 -0
- data/template/config/build.yml +8 -0
- data/template/lib/application.rb +45 -0
- data/template/lib/menu.rb +32 -0
- data/template/resources/HotCocoa.icns +0 -0
- data/test/test_helper.rb +3 -0
- data/test/test_hotcocoa.rb +11 -0
- metadata +137 -0
data/History.txt
ADDED
data/bin/hotcocoa
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env macruby
|
2
|
+
|
3
|
+
project_name = ARGV.shift
|
4
|
+
|
5
|
+
if project_name.nil? or project_name == "--help" or project_name =="-h"
|
6
|
+
puts "Usage: hotcocoa <project name>"
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
if File.exist?(project_name)
|
11
|
+
if File.extname(project_name) == ".rb"
|
12
|
+
file_to_copy = project_name
|
13
|
+
project_name = project_name[0..-4]
|
14
|
+
else
|
15
|
+
puts %{Error: "#{project_name}" already exists in this directory.}
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
else
|
19
|
+
file_to_copy = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'hotcocoa/template'
|
23
|
+
HotCocoa::Template.copy_to(project_name, project_name.split("_").collect(&:capitalize).join(" "))
|
24
|
+
|
25
|
+
if file_to_copy
|
26
|
+
lib_dir = File.join(project_name, "lib")
|
27
|
+
File.open(File.join(lib_dir, "application.rb"), "w") do |file|
|
28
|
+
file.write File.read(file_to_copy)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,320 @@
|
|
1
|
+
framework 'Foundation'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module HotCocoa
|
6
|
+
|
7
|
+
class ApplicationBuilder
|
8
|
+
|
9
|
+
class Configuration
|
10
|
+
|
11
|
+
attr_reader :name, :version, :icon, :resources, :sources, :info_string, :load
|
12
|
+
|
13
|
+
def initialize(file)
|
14
|
+
require 'yaml'
|
15
|
+
yml = YAML.load(File.read(file))
|
16
|
+
@name = yml["name"]
|
17
|
+
@load = yml["load"]
|
18
|
+
@version = yml["version"] || "1.0"
|
19
|
+
@icon = yml["icon"]
|
20
|
+
@info_string = yml["info_string"]
|
21
|
+
@sources = yml["sources"] || []
|
22
|
+
@resources = yml["resources"] || []
|
23
|
+
@overwrite = yml["overwrite"] == true ? true : false
|
24
|
+
@secure = yml["secure"] == true ? true : false
|
25
|
+
end
|
26
|
+
|
27
|
+
def overwrite?
|
28
|
+
@overwrite
|
29
|
+
end
|
30
|
+
|
31
|
+
def secure?
|
32
|
+
@secure
|
33
|
+
end
|
34
|
+
|
35
|
+
def icon_exist?
|
36
|
+
@icon ? File.exist?(@icon) : false
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
ApplicationBundlePackage = "APPL????"
|
42
|
+
|
43
|
+
attr_accessor :name, :load_file, :sources, :overwrite, :icon, :version, :info_string, :secure, :resources, :deploy
|
44
|
+
|
45
|
+
def self.build(config, options={:deploy => false})
|
46
|
+
if !config.kind_of?(Configuration) || !$LOADED_FEATURES.detect {|f| f.include?("standard_rake_tasks")}
|
47
|
+
require 'rbconfig'
|
48
|
+
puts "Your Rakefile needs to be updated. Please copy the Rakefile from:"
|
49
|
+
puts File.expand_path(File.join(Config::CONFIG['datadir'], "hotcocoa_template", "Rakefile"))
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
builder = new
|
53
|
+
builder.deploy = options[:deploy] == true ? true : false
|
54
|
+
builder.secure = config.secure?
|
55
|
+
builder.name = config.name
|
56
|
+
builder.load_file = config.load
|
57
|
+
builder.icon = config.icon if config.icon_exist?
|
58
|
+
builder.version = config.version
|
59
|
+
builder.info_string = config.info_string
|
60
|
+
builder.overwrite = config.overwrite?
|
61
|
+
config.sources.each do |source|
|
62
|
+
builder.add_source_path source
|
63
|
+
end
|
64
|
+
config.resources.each do |resource|
|
65
|
+
builder.add_resource_path resource
|
66
|
+
end
|
67
|
+
builder.build
|
68
|
+
end
|
69
|
+
|
70
|
+
# Used by the "Embed MacRuby" Xcode target.
|
71
|
+
def self.deploy(path)
|
72
|
+
raise "Given path `#{path}' does not exist" unless File.exist?(path)
|
73
|
+
raise "Given path `#{path}' does not look like an application bundle" unless File.extname(path) == '.app'
|
74
|
+
deployer = new
|
75
|
+
Dir.chdir(File.dirname(path)) do
|
76
|
+
deployer.name = File.basename(path, '.app')
|
77
|
+
deployer.deploy
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize
|
82
|
+
@sources = []
|
83
|
+
@resources = []
|
84
|
+
end
|
85
|
+
|
86
|
+
def build
|
87
|
+
check_for_bundle_root
|
88
|
+
build_bundle_structure
|
89
|
+
write_bundle_files
|
90
|
+
copy_sources
|
91
|
+
copy_resources
|
92
|
+
deploy if deploy?
|
93
|
+
copy_icon_file if icon
|
94
|
+
end
|
95
|
+
|
96
|
+
def deploy
|
97
|
+
copy_framework
|
98
|
+
end
|
99
|
+
|
100
|
+
def deploy?
|
101
|
+
@deploy
|
102
|
+
end
|
103
|
+
|
104
|
+
def overwrite?
|
105
|
+
@overwrite
|
106
|
+
end
|
107
|
+
|
108
|
+
def add_source_path(source_file_pattern)
|
109
|
+
Dir.glob(source_file_pattern).each do |source_file|
|
110
|
+
sources << source_file
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_resource_path(resource_file_pattern)
|
115
|
+
Dir.glob(resource_file_pattern).each do |resource_file|
|
116
|
+
resources << resource_file
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def secure?
|
121
|
+
secure
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def check_for_bundle_root
|
127
|
+
if File.exist?(bundle_root) && overwrite?
|
128
|
+
`rm -rf #{bundle_root}`
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def build_bundle_structure
|
133
|
+
Dir.mkdir(bundle_root) unless File.exist?(bundle_root)
|
134
|
+
Dir.mkdir(contents_root) unless File.exist?(contents_root)
|
135
|
+
Dir.mkdir(frameworks_root) unless File.exist?(frameworks_root)
|
136
|
+
Dir.mkdir(macos_root) unless File.exist?(macos_root)
|
137
|
+
Dir.mkdir(resources_root) unless File.exist?(resources_root)
|
138
|
+
end
|
139
|
+
|
140
|
+
def write_bundle_files
|
141
|
+
write_pkg_info_file
|
142
|
+
write_info_plist_file
|
143
|
+
build_executable unless File.exist?(File.join(macos_root, objective_c_executable_file))
|
144
|
+
write_ruby_main
|
145
|
+
end
|
146
|
+
|
147
|
+
def copy_framework
|
148
|
+
unless File.exist?(File.join(frameworks_root, 'MacRuby.framework'))
|
149
|
+
FileUtils.mkdir_p frameworks_root
|
150
|
+
FileUtils.cp_r macruby_framework_path, frameworks_root
|
151
|
+
end
|
152
|
+
`install_name_tool -change #{current_macruby_path}/usr/lib/libmacruby.dylib @executable_path/../Frameworks/MacRuby.framework/Versions/#{current_macruby_version}/usr/lib/libmacruby.dylib '#{macos_root}/#{objective_c_executable_file}'`
|
153
|
+
end
|
154
|
+
|
155
|
+
def copy_sources
|
156
|
+
if secure?
|
157
|
+
data = {}
|
158
|
+
data["/"+load_file] = File.open(load_file, "r") {|f| f.read}
|
159
|
+
sources.each do |source|
|
160
|
+
data["/"+source] = File.open(source, "r") {|f| f.read}
|
161
|
+
end
|
162
|
+
File.open(File.join(resources_root, "vfs.db"), "wb") do |db|
|
163
|
+
db.write Marshal.dump(data)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
FileUtils.cp_r load_file, resources_root unless sources.include?(load_file)
|
167
|
+
sources.each do |source|
|
168
|
+
destination = File.join(resources_root, source)
|
169
|
+
FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
|
170
|
+
FileUtils.cp_r source, destination
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def copy_resources
|
176
|
+
resources.each do |resource|
|
177
|
+
destination = File.join(resources_root, resource.split("/")[1..-1].join("/"))
|
178
|
+
FileUtils.mkdir_p(File.dirname(destination)) unless File.exist?(File.dirname(destination))
|
179
|
+
FileUtils.cp_r resource, destination
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def copy_icon_file
|
184
|
+
FileUtils.cp(icon, icon_file) unless File.exist?(icon_file)
|
185
|
+
end
|
186
|
+
|
187
|
+
def write_pkg_info_file
|
188
|
+
File.open(pkg_info_file, "wb") {|f| f.write ApplicationBundlePackage}
|
189
|
+
end
|
190
|
+
|
191
|
+
def write_info_plist_file
|
192
|
+
File.open(info_plist_file, "w") do |f|
|
193
|
+
f.puts %{<?xml version="1.0" encoding="UTF-8"?>}
|
194
|
+
f.puts %{<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">}
|
195
|
+
f.puts %{<plist version="1.0">}
|
196
|
+
f.puts %{<dict>}
|
197
|
+
f.puts %{ <key>CFBundleDevelopmentRegion</key>}
|
198
|
+
f.puts %{ <string>English</string>}
|
199
|
+
f.puts %{ <key>CFBundleIconFile</key>} if icon
|
200
|
+
f.puts %{ <string>#{name}.icns</string>} if icon
|
201
|
+
f.puts %{ <key>CFBundleGetInfoString</key>} if info_string
|
202
|
+
f.puts %{ <string>#{info_string}</string>} if info_string
|
203
|
+
f.puts %{ <key>CFBundleExecutable</key>}
|
204
|
+
f.puts %{ <string>#{name.gsub(/ /, '')}</string>}
|
205
|
+
f.puts %{ <key>CFBundleIdentifier</key>}
|
206
|
+
f.puts %{ <string>com.yourcompany.#{name}</string>}
|
207
|
+
f.puts %{ <key>CFBundleInfoDictionaryVersion</key>}
|
208
|
+
f.puts %{ <string>6.0</string>}
|
209
|
+
f.puts %{ <key>CFBundleName</key>}
|
210
|
+
f.puts %{ <string>#{name}</string>}
|
211
|
+
f.puts %{ <key>CFBundlePackageType</key>}
|
212
|
+
f.puts %{ <string>APPL</string>}
|
213
|
+
f.puts %{ <key>CFBundleSignature</key>}
|
214
|
+
f.puts %{ <string>????</string>}
|
215
|
+
f.puts %{ <key>CFBundleVersion</key>}
|
216
|
+
f.puts %{ <string>#{version}</string>}
|
217
|
+
f.puts %{ <key>NSPrincipalClass</key>}
|
218
|
+
f.puts %{ <string>NSApplication</string>}
|
219
|
+
f.puts %{</dict>}
|
220
|
+
f.puts %{</plist>}
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def build_executable
|
225
|
+
File.open(objective_c_source_file, "wb") do |f|
|
226
|
+
f.puts %{
|
227
|
+
|
228
|
+
#import <MacRuby/MacRuby.h>
|
229
|
+
|
230
|
+
int main(int argc, char *argv[])
|
231
|
+
{
|
232
|
+
return macruby_main("rb_main.rb", argc, argv);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
end
|
236
|
+
archs = RUBY_ARCH.include?('ppc') ? '-arch ppc' : '-arch i386 -arch x86_64'
|
237
|
+
puts `cd "#{macos_root}" && gcc main.m -o #{objective_c_executable_file} #{archs} -framework MacRuby -framework Foundation -fobjc-gc-only`
|
238
|
+
File.unlink(objective_c_source_file)
|
239
|
+
end
|
240
|
+
|
241
|
+
def write_ruby_main
|
242
|
+
File.open(main_ruby_source_file, "wb") do |f|
|
243
|
+
if secure?
|
244
|
+
require 'hotcocoa/virtual_file_system'
|
245
|
+
f.puts VirtualFileSystem.code_to_load(load_file)
|
246
|
+
else
|
247
|
+
f.puts "$:.map! { |x| x.sub(/^\\/Library\\/Frameworks/, NSBundle.mainBundle.privateFrameworksPath) }" if deploy?
|
248
|
+
f.puts "$:.unshift NSBundle.mainBundle.resourcePath.fileSystemRepresentation"
|
249
|
+
f.puts "load '#{load_file}'"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def bundle_root
|
255
|
+
"#{name}.app"
|
256
|
+
end
|
257
|
+
|
258
|
+
def contents_root
|
259
|
+
File.join(bundle_root, "Contents")
|
260
|
+
end
|
261
|
+
|
262
|
+
def frameworks_root
|
263
|
+
File.join(contents_root, "Frameworks")
|
264
|
+
end
|
265
|
+
|
266
|
+
def macos_root
|
267
|
+
File.join(contents_root, "MacOS")
|
268
|
+
end
|
269
|
+
|
270
|
+
def resources_root
|
271
|
+
File.join(contents_root, "Resources")
|
272
|
+
end
|
273
|
+
|
274
|
+
def bridgesupport_root
|
275
|
+
File.join(resources_root, "BridgeSupport")
|
276
|
+
end
|
277
|
+
|
278
|
+
def info_plist_file
|
279
|
+
File.join(contents_root, "Info.plist")
|
280
|
+
end
|
281
|
+
|
282
|
+
def icon_file
|
283
|
+
File.join(resources_root, "#{name}.icns")
|
284
|
+
end
|
285
|
+
|
286
|
+
def pkg_info_file
|
287
|
+
File.join(contents_root, "PkgInfo")
|
288
|
+
end
|
289
|
+
|
290
|
+
def objective_c_executable_file
|
291
|
+
name.gsub(/ /, '')
|
292
|
+
end
|
293
|
+
|
294
|
+
def objective_c_source_file
|
295
|
+
File.join(macos_root, "main.m")
|
296
|
+
end
|
297
|
+
|
298
|
+
def main_ruby_source_file
|
299
|
+
File.join(resources_root, "rb_main.rb")
|
300
|
+
end
|
301
|
+
|
302
|
+
def current_macruby_version
|
303
|
+
NSFileManager.defaultManager.pathContentOfSymbolicLinkAtPath(File.join(macruby_versions_path, "Current"))
|
304
|
+
end
|
305
|
+
|
306
|
+
def current_macruby_path
|
307
|
+
File.join(macruby_versions_path, current_macruby_version)
|
308
|
+
end
|
309
|
+
|
310
|
+
def macruby_versions_path
|
311
|
+
File.join(macruby_framework_path, "Versions")
|
312
|
+
end
|
313
|
+
|
314
|
+
def macruby_framework_path
|
315
|
+
"/Library/Frameworks/MacRuby.framework"
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module HotCocoa
|
2
|
+
class NSRangedProxyAttributeHash
|
3
|
+
ATTRIBUTE_KEYS = { :font => NSFontAttributeName,
|
4
|
+
:paragraph_style => NSParagraphStyleAttributeName,
|
5
|
+
:color => NSForegroundColorAttributeName,
|
6
|
+
:underline_style => NSUnderlineStyleAttributeName,
|
7
|
+
:superscript => NSSuperscriptAttributeName,
|
8
|
+
:background_color => NSBackgroundColorAttributeName,
|
9
|
+
:attachment => NSAttachmentAttributeName,
|
10
|
+
:ligature => NSLigatureAttributeName,
|
11
|
+
:baseline_offset => NSBaselineOffsetAttributeName,
|
12
|
+
:kerning => NSKernAttributeName,
|
13
|
+
:link => NSLinkAttributeName,
|
14
|
+
:stroke_width => NSStrokeWidthAttributeName,
|
15
|
+
:stroke_color => NSStrokeColorAttributeName,
|
16
|
+
:underline_color => NSUnderlineColorAttributeName,
|
17
|
+
:strikethrough_style => NSStrikethroughStyleAttributeName,
|
18
|
+
:strikethrough_color => NSStrikethroughColorAttributeName,
|
19
|
+
:shadow => NSShadowAttributeName,
|
20
|
+
:obliqueness => NSObliquenessAttributeName,
|
21
|
+
:expansion_factor => NSExpansionAttributeName,
|
22
|
+
:cursor => NSCursorAttributeName,
|
23
|
+
:tool_tip => NSToolTipAttributeName,
|
24
|
+
:character_shape => NSCharacterShapeAttributeName,
|
25
|
+
:glyph_info => NSGlyphInfoAttributeName,
|
26
|
+
:marked_clause_segment => NSMarkedClauseSegmentAttributeName,
|
27
|
+
:spelling_state => NSSpellingStateAttributeName }
|
28
|
+
|
29
|
+
|
30
|
+
def initialize(proxy)
|
31
|
+
@proxy = proxy
|
32
|
+
end
|
33
|
+
|
34
|
+
def [](k)
|
35
|
+
k = attribute_for_key(k)
|
36
|
+
@proxy.string.attribute(k, atIndex:@proxy.range.first, effectiveRange:nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def []=(k,v)
|
40
|
+
k = attribute_for_key(k)
|
41
|
+
@proxy.string.removeAttribute(k, range:@proxy.range.to_NSRange(@proxy.string.length - 1))
|
42
|
+
@proxy.string.addAttribute(k, value:v, range:@proxy.range.to_NSRange(@proxy.string.length - 1))
|
43
|
+
end
|
44
|
+
|
45
|
+
def <<(attributes)
|
46
|
+
attributes.each_pair do |k, v|
|
47
|
+
self[k] = v
|
48
|
+
end
|
49
|
+
self
|
50
|
+
end
|
51
|
+
alias :merge :<<
|
52
|
+
|
53
|
+
def to_hash
|
54
|
+
@proxy.string.attributesAtIndex(@proxy.range.first, effectiveRange:nil).inject({}) do |h, pair|
|
55
|
+
h[key_for_attribute(pair.first)] = pair.last
|
56
|
+
h
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def inspect
|
61
|
+
to_hash.inspect
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def key_for_attribute(attribute)
|
66
|
+
(ATTRIBUTE_KEYS.select { |k,v| v == attribute }.first || [attribute]).first
|
67
|
+
end
|
68
|
+
|
69
|
+
def attribute_for_key(key)
|
70
|
+
ATTRIBUTE_KEYS[key] || key
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class NSRangedProxyAttributedString
|
75
|
+
attr_reader :string, :range
|
76
|
+
def initialize(string, range)
|
77
|
+
@string = string
|
78
|
+
@range = range
|
79
|
+
end
|
80
|
+
|
81
|
+
def attributes
|
82
|
+
NSRangedProxyAttributeHash.new(self)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class String
|
88
|
+
def with_attributes(attributes = {})
|
89
|
+
attributed_string = NSMutableAttributedString.alloc.initWithString(self)
|
90
|
+
attributed_string.attributes << attributes
|
91
|
+
attributed_string
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Range
|
96
|
+
def to_NSRange(max = nil)
|
97
|
+
location = first
|
98
|
+
if last == -1 and max
|
99
|
+
length = max - first + 1
|
100
|
+
else
|
101
|
+
length = last - first + 1
|
102
|
+
end
|
103
|
+
NSRange.new(location, length)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class NSMutableAttributedString
|
108
|
+
def with_attributes(attributes = {})
|
109
|
+
string.with_attributes(attributes)
|
110
|
+
end
|
111
|
+
|
112
|
+
def <<(s)
|
113
|
+
case s
|
114
|
+
when String
|
115
|
+
mutableString.appendString s
|
116
|
+
else
|
117
|
+
appendAttributedString s
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def +(s)
|
122
|
+
attributed_string = mutableCopy
|
123
|
+
attributed_string << s
|
124
|
+
attributed_string
|
125
|
+
end
|
126
|
+
|
127
|
+
def attributes
|
128
|
+
HotCocoa::NSRangedProxyAttributedString.new(self, 0..-1).attributes
|
129
|
+
end
|
130
|
+
|
131
|
+
def [](r)
|
132
|
+
HotCocoa::NSRangedProxyAttributedString.new(self, r)
|
133
|
+
end
|
134
|
+
|
135
|
+
def []=(r, s)
|
136
|
+
case s
|
137
|
+
when String
|
138
|
+
replaceCharactersInRange(r.to_NSRange(length - 1), :withString => s)
|
139
|
+
else
|
140
|
+
replaceCharactersInRange(r.to_NSRange(length - 1), :withAttributedString => s)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module HotCocoa
|
2
|
+
class ComboBoxDataSource
|
3
|
+
attr_reader :data
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def comboBox(combo_box, completedString:string)
|
10
|
+
data.length.times do |index|
|
11
|
+
value = string_value_of_index(index)
|
12
|
+
return value if value.start_with?(string)
|
13
|
+
end
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def comboBox(combo_box, indexOfItemWithStringValue:string)
|
18
|
+
data.length.times do |index|
|
19
|
+
return index if string_value_of_index(index) == string
|
20
|
+
end
|
21
|
+
NSNotFound
|
22
|
+
end
|
23
|
+
|
24
|
+
def comboBox(combo_box, objectValueForItemAtIndex:index)
|
25
|
+
string_value_of_index(index)
|
26
|
+
end
|
27
|
+
|
28
|
+
def numberOfItemsInComboBox(combo_box)
|
29
|
+
data.length
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def string_value_of_index(i)
|
35
|
+
item = data[i]
|
36
|
+
if item.kind_of?(Hash)
|
37
|
+
item.values.first
|
38
|
+
else
|
39
|
+
item.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module HotCocoa
|
2
|
+
class TableDataSource
|
3
|
+
attr_reader :data
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
end
|
8
|
+
|
9
|
+
def numberOfRowsInTableView(tableView)
|
10
|
+
data.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def tableView(view, objectValueForTableColumn:column, row:i)
|
14
|
+
data[i][column.identifier.intern]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module HotCocoa
|
2
|
+
|
3
|
+
class DelegateBuilder
|
4
|
+
|
5
|
+
attr_reader :control, :delegate, :method_count, :required_methods
|
6
|
+
|
7
|
+
def initialize(control, required_methods)
|
8
|
+
@control = control
|
9
|
+
@required_methods = required_methods
|
10
|
+
@method_count = 0
|
11
|
+
@delegate = Object.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_delegated_method(block, selector_name, *parameters)
|
15
|
+
clear_delegate if required_methods.empty?
|
16
|
+
increment_method_count
|
17
|
+
bind_block_to_delegate_instance_variable(block)
|
18
|
+
create_delegate_method(selector_name, parameters)
|
19
|
+
set_delegate if required_methods.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def delegate_to(object, *method_names)
|
23
|
+
method_names.each do |method_name|
|
24
|
+
control.send(method_name, &object.method(method_name)) if object.respond_to?(method_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def increment_method_count
|
31
|
+
@method_count += 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def bind_block_to_delegate_instance_variable(block)
|
35
|
+
delegate.instance_variable_set(block_instance_variable, block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_delegate_method(selector_name, parameters)
|
39
|
+
required_methods.delete(selector_name)
|
40
|
+
eval %{
|
41
|
+
def delegate.#{parameterize_selector_name(selector_name)}
|
42
|
+
#{block_instance_variable}.call(#{parameter_values_for_mapping(selector_name, parameters)})
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def clear_delegate
|
48
|
+
control.setDelegate(nil) if control.delegate
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_delegate
|
52
|
+
control.setDelegate(delegate)
|
53
|
+
end
|
54
|
+
|
55
|
+
def block_instance_variable
|
56
|
+
"@block#{method_count}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def parameterize_selector_name(selector_name)
|
60
|
+
return selector_name unless selector_name.include?(":")
|
61
|
+
params = selector_name.split(":")
|
62
|
+
result = "#{params.shift}(p1"
|
63
|
+
params.each_with_index do |param, i|
|
64
|
+
result << ", #{param}:p#{i+2}"
|
65
|
+
end
|
66
|
+
result + ")"
|
67
|
+
end
|
68
|
+
|
69
|
+
def parameter_values_for_mapping(selector_name, parameters)
|
70
|
+
return if parameters.empty?
|
71
|
+
result = []
|
72
|
+
selector_params = selector_name.split(":")
|
73
|
+
parameters.each do |parameter|
|
74
|
+
if (dot = parameter.index("."))
|
75
|
+
result << "p#{selector_params.index(parameter[0...dot])+1}#{parameter[dot..-1]}"
|
76
|
+
else
|
77
|
+
result << "p#{selector_params.index(parameter)+1}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
result.join(", ")
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|