hotcocoa 0.5
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.
- 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
|