cura 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +15 -0
  3. data/Gemfile.lock +122 -0
  4. data/LICENSE +20 -0
  5. data/README.md +159 -0
  6. data/Rakefile +42 -0
  7. data/cura.gemspec +23 -0
  8. data/examples/box_model/bin/box_model +11 -0
  9. data/examples/box_model/debug.log +0 -0
  10. data/examples/box_model/lib/box_model.rb +21 -0
  11. data/examples/box_model/lib/box_model/application.rb +24 -0
  12. data/examples/hello_world/bin/hello_world +10 -0
  13. data/examples/hello_world/lib/hello_world.rb +201 -0
  14. data/examples/mruby-examples/README.md +10 -0
  15. data/examples/mruby-examples/include/cura_examples.h +6 -0
  16. data/examples/mruby-examples/mrbgem.rake +14 -0
  17. data/examples/mruby-examples/src/gem_init.c +34 -0
  18. data/examples/mruby-examples/tools/hello_world/hello_world.c +6 -0
  19. data/examples/todo_list/app.log +9 -0
  20. data/examples/todo_list/bin/todo_list +26 -0
  21. data/examples/todo_list/data.db +0 -0
  22. data/examples/todo_list/debug.log +0 -0
  23. data/examples/todo_list/lib/todo_list.rb +28 -0
  24. data/examples/todo_list/lib/todo_list/application.rb +54 -0
  25. data/examples/todo_list/lib/todo_list/component/header.rb +27 -0
  26. data/examples/todo_list/lib/todo_list/component/list.rb +50 -0
  27. data/examples/todo_list/lib/todo_list/component/list_item.rb +28 -0
  28. data/examples/todo_list/lib/todo_list/component/list_items.rb +97 -0
  29. data/examples/todo_list/lib/todo_list/component/lists.rb +89 -0
  30. data/examples/todo_list/lib/todo_list/database.rb +50 -0
  31. data/examples/todo_list/lib/todo_list/model/list.rb +9 -0
  32. data/examples/todo_list/lib/todo_list/model/list_item.rb +9 -0
  33. data/examples/todo_list/profile.html +11354 -0
  34. data/lib/cura.rb +13 -0
  35. data/lib/cura/adapter.rb +67 -0
  36. data/lib/cura/application.rb +245 -0
  37. data/lib/cura/attributes/has_ancestry.rb +40 -0
  38. data/lib/cura/attributes/has_application.rb +31 -0
  39. data/lib/cura/attributes/has_attributes.rb +89 -0
  40. data/lib/cura/attributes/has_children.rb +113 -0
  41. data/lib/cura/attributes/has_colors.rb +66 -0
  42. data/lib/cura/attributes/has_coordinates.rb +49 -0
  43. data/lib/cura/attributes/has_dimensions.rb +63 -0
  44. data/lib/cura/attributes/has_events.rb +89 -0
  45. data/lib/cura/attributes/has_focusability.rb +37 -0
  46. data/lib/cura/attributes/has_initialize.rb +15 -0
  47. data/lib/cura/attributes/has_offsets.rb +82 -0
  48. data/lib/cura/attributes/has_orientation.rb +53 -0
  49. data/lib/cura/attributes/has_relative_coordinates.rb +39 -0
  50. data/lib/cura/attributes/has_root.rb +104 -0
  51. data/lib/cura/attributes/has_side_attributes.rb +95 -0
  52. data/lib/cura/attributes/has_windows.rb +70 -0
  53. data/lib/cura/borders.rb +16 -0
  54. data/lib/cura/color.rb +330 -0
  55. data/lib/cura/component/base.rb +180 -0
  56. data/lib/cura/component/button.rb +57 -0
  57. data/lib/cura/component/group.rb +77 -0
  58. data/lib/cura/component/label.rb +224 -0
  59. data/lib/cura/component/listbox.rb +152 -0
  60. data/lib/cura/component/pack.rb +144 -0
  61. data/lib/cura/component/scrollbar.rb +184 -0
  62. data/lib/cura/component/textbox.rb +118 -0
  63. data/lib/cura/cursor.rb +77 -0
  64. data/lib/cura/error/base.rb +10 -0
  65. data/lib/cura/error/invalid_adapter.rb +18 -0
  66. data/lib/cura/error/invalid_application.rb +18 -0
  67. data/lib/cura/error/invalid_color.rb +18 -0
  68. data/lib/cura/error/invalid_component.rb +18 -0
  69. data/lib/cura/error/invalid_middleware.rb +18 -0
  70. data/lib/cura/event.rb +38 -0
  71. data/lib/cura/event/base.rb +108 -0
  72. data/lib/cura/event/click.rb +14 -0
  73. data/lib/cura/event/dispatcher.rb +122 -0
  74. data/lib/cura/event/focus.rb +14 -0
  75. data/lib/cura/event/handler.rb +74 -0
  76. data/lib/cura/event/key_down.rb +68 -0
  77. data/lib/cura/event/middleware/aimer/base.rb +38 -0
  78. data/lib/cura/event/middleware/aimer/dispatcher_target.rb +24 -0
  79. data/lib/cura/event/middleware/aimer/mouse_focus.rb +48 -0
  80. data/lib/cura/event/middleware/aimer/target_option.rb +38 -0
  81. data/lib/cura/event/middleware/base.rb +21 -0
  82. data/lib/cura/event/middleware/dispatch.rb +20 -0
  83. data/lib/cura/event/middleware/translator/base.rb +37 -0
  84. data/lib/cura/event/middleware/translator/mouse_click.rb +44 -0
  85. data/lib/cura/event/mouse.rb +34 -0
  86. data/lib/cura/event/mouse_button.rb +103 -0
  87. data/lib/cura/event/mouse_wheel_down.rb +14 -0
  88. data/lib/cura/event/mouse_wheel_up.rb +14 -0
  89. data/lib/cura/event/resize.rb +17 -0
  90. data/lib/cura/event/selected.rb +14 -0
  91. data/lib/cura/event/unfocus.rb +14 -0
  92. data/lib/cura/focus_controller.rb +89 -0
  93. data/lib/cura/key.rb +313 -0
  94. data/lib/cura/margins.rb +16 -0
  95. data/lib/cura/offsets.rb +91 -0
  96. data/lib/cura/padding.rb +16 -0
  97. data/lib/cura/pencil.rb +29 -0
  98. data/lib/cura/version.rb +6 -0
  99. data/lib/cura/window.rb +85 -0
  100. data/spec/cura/attributes/has_ancestry_spec.rb +108 -0
  101. data/spec/cura/attributes/has_application_spec.rb +59 -0
  102. data/spec/cura/attributes/has_attributes_spec.rb +75 -0
  103. data/spec/cura/attributes/has_children_spec.rb +169 -0
  104. data/spec/cura/attributes/has_colors_spec.rb +20 -0
  105. data/spec/cura/attributes/has_coordinates_spec.rb +19 -0
  106. data/spec/cura/attributes/has_dimensions_spec.rb +19 -0
  107. data/spec/cura/attributes/has_events_spec.rb +18 -0
  108. data/spec/cura/attributes/has_focusability_spec.rb +58 -0
  109. data/spec/cura/attributes/has_offsets_spec.rb +18 -0
  110. data/spec/cura/attributes/has_orientation_spec.rb +102 -0
  111. data/spec/cura/attributes/has_relative_coordinates_spec.rb +18 -0
  112. data/spec/cura/attributes/has_side_attributes_spec.rb +19 -0
  113. data/spec/spec_helper.rb +12 -0
  114. data/spec/support/shared_examples_for_attributes.rb +122 -0
  115. metadata +211 -0
@@ -0,0 +1,13 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/version"
3
+ require "cura/adapter"
4
+ require "cura/application"
5
+ require "cura/window"
6
+ require "cura/component/group"
7
+ require "cura/component/pack"
8
+ require "cura/component/label"
9
+ require "cura/component/button"
10
+ require "cura/component/listbox"
11
+ # require 'cura/component/scrollbar'
12
+ require "cura/component/textbox"
13
+ end
@@ -0,0 +1,67 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_initialize"
3
+ require "cura/attributes/has_attributes"
4
+ end
5
+
6
+ module Cura
7
+
8
+ # The base class for adapters.
9
+ class Adapter
10
+
11
+ class << self
12
+
13
+ # The list of all Adapter subclasses.
14
+ #
15
+ # @return [Array]
16
+ def all
17
+ @all ||= []
18
+ end
19
+
20
+ def inherited(subclass)
21
+ all << subclass
22
+ end
23
+
24
+ def mixins
25
+ @mixins ||= {}
26
+ end
27
+
28
+ def mixin(value)
29
+ mixins.merge!(value.to_h)
30
+ end
31
+
32
+ end
33
+
34
+ include Attributes::HasInitialize
35
+ include Attributes::HasAttributes
36
+
37
+ def initialize(attributes={})
38
+ @setup = false
39
+
40
+ super
41
+ end
42
+
43
+ def setup
44
+ @setup = true
45
+
46
+ self.class.mixins.each { |type, mod| type.send(:include, mod) }
47
+
48
+ self
49
+ end
50
+
51
+ def setup?
52
+ @setup
53
+ end
54
+
55
+ def clear
56
+
57
+ end
58
+
59
+ def cleanup
60
+ @setup = false
61
+
62
+ self
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,245 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_attributes"
3
+ require "cura/attributes/has_windows"
4
+ require "cura/attributes/has_events"
5
+ require "cura/attributes/has_initialize"
6
+
7
+ require "cura/component/base"
8
+
9
+ require "cura/event/dispatcher"
10
+
11
+ require "cura/event/click"
12
+ require "cura/event/focus"
13
+ require "cura/event/unfocus"
14
+ require "cura/event/handler"
15
+ require "cura/event/key_down"
16
+ require "cura/event/mouse_button"
17
+ require "cura/event/mouse_wheel_down"
18
+ require "cura/event/mouse_wheel_up"
19
+ require "cura/event/resize"
20
+ require "cura/event/selected"
21
+
22
+ require "cura/event/middleware/dispatch"
23
+ require "cura/event/middleware/aimer/mouse_focus"
24
+ require "cura/event/middleware/aimer/target_option"
25
+ require "cura/event/middleware/aimer/dispatcher_target"
26
+ require "cura/event/middleware/translator/mouse_click"
27
+
28
+ require "cura/error/invalid_adapter"
29
+
30
+ require "cura/cursor"
31
+ require "cura/pencil"
32
+ end
33
+
34
+ module Cura
35
+
36
+ # An application.
37
+ class Application
38
+
39
+ class << self
40
+
41
+ def run(attributes={})
42
+ new(attributes).run
43
+ end
44
+
45
+ end
46
+
47
+ include Attributes::HasInitialize
48
+ include Attributes::HasAttributes
49
+ include Attributes::HasWindows
50
+ include Attributes::HasEvents
51
+
52
+ def initialize(attributes={})
53
+ super
54
+
55
+ @running = false
56
+ @cursor = Cursor.new(application: self)
57
+ @pencil = Pencil.new
58
+
59
+ setup_adapter
60
+ setup_dispatcher
61
+ end
62
+
63
+ # @method adapter
64
+ # Get the adapter used for running this application.
65
+ #
66
+ # @return [Adapter]
67
+
68
+ # @method adapter=(adapter)
69
+ # Set the adapter used for running this application.
70
+ # This cannot be set after #run is used.
71
+ #
72
+ # @param [Adapter] value The new adapter.
73
+ # @return [Adapter]
74
+
75
+ attribute(:adapter) { |adapter| validate_adapter(adapter) }
76
+
77
+ # Get the text cursor.
78
+ #
79
+ # @return [Cursor]
80
+ attr_reader :cursor
81
+
82
+ # Get the pencil used for drawing.
83
+ #
84
+ # @return [Pencil]
85
+ attr_reader :pencil
86
+
87
+ # Get the event dispatcher.
88
+ #
89
+ # @return [Event::Dispatcher]
90
+ attr_reader :dispatcher
91
+
92
+ # Run this application.
93
+ #
94
+ # @return [Application] This application.
95
+ def run
96
+ run_event_loop
97
+
98
+ self
99
+ ensure
100
+ @adapter.cleanup
101
+ end
102
+
103
+ # Stop the application after the current run cycle.
104
+ #
105
+ # @return [Application] This application.
106
+ def stop
107
+ @running = false
108
+
109
+ self
110
+ end
111
+
112
+ # Stop the application immediently.
113
+ #
114
+ # @return [Application] This application.
115
+ def stop!
116
+ stop
117
+ @adapter.cleanup
118
+
119
+ self
120
+ end
121
+
122
+ # Check if this application is running.
123
+ #
124
+ # @return [Boolean]
125
+ def running?
126
+ @running
127
+ end
128
+
129
+ # Get the currently focused component.
130
+ #
131
+ # @return [Component::Base]
132
+ def focused
133
+ @dispatcher.target
134
+ end
135
+
136
+ # Set focus to a component.
137
+ #
138
+ # There can only be one component focused at a time within an application, if any.
139
+ # All dispatched events are sent to the currently focused component, or the application if no component is focused.
140
+ #
141
+ # @param [nil, Component::Base] component
142
+ # @return [Component::Base]
143
+ def focus(component)
144
+ raise TypeError, "component must be nil or be a Cura::Component::Base" unless component.nil? || component.is_a?(Cura::Component::Base)
145
+
146
+ dispatch_event(:unfocus)
147
+ @dispatcher.target = component
148
+ dispatch_event(:focus)
149
+
150
+ component
151
+ end
152
+
153
+ # Dispatch an event.
154
+ #
155
+ # @param [#to_sym] event The name of the event class to create an instance of or an event instance.
156
+ # @param [#to_hash, #to_h] options
157
+ # @option options [#to_i] :target The optional target of the event.
158
+ # @return [Event::Base] The dispatched event.
159
+ def dispatch_event(event, options={})
160
+ @dispatcher.dispatch_event(event, options)
161
+ end
162
+
163
+ # Add a window to this application.
164
+ #
165
+ # @param [Window] window
166
+ # @return [Window]
167
+ def add_window(window)
168
+ super
169
+
170
+ window.application = self
171
+
172
+ window
173
+ end
174
+
175
+ # Update all windows.
176
+ #
177
+ # @return [Application]
178
+ def update
179
+ update_windows
180
+ cursor.update
181
+
182
+ self
183
+ end
184
+
185
+ # Draw all windows.
186
+ #
187
+ # @return [Application]
188
+ def draw
189
+ draw_windows
190
+
191
+ self
192
+ end
193
+
194
+ # Instance inspection.
195
+ #
196
+ # @return [String]
197
+ def inspect
198
+ "#<#{self.class}>"
199
+ end
200
+
201
+ protected
202
+
203
+ def setup_adapter
204
+ if @adapter.nil?
205
+ adapter_class ||= Adapter.all.first
206
+ raise Error::InvalidAdapter if adapter_class.nil?
207
+
208
+ @adapter = adapter_class.new
209
+ end
210
+
211
+ # TODO: If a class is given, run .new on it first
212
+
213
+ @adapter.setup
214
+ end
215
+
216
+ def setup_dispatcher
217
+ @dispatcher = Event::Dispatcher.new(application: self)
218
+
219
+ @dispatcher.middleware << Event::Middleware::Aimer::MouseFocus.new
220
+ @dispatcher.middleware << Event::Middleware::Aimer::TargetOption.new
221
+ @dispatcher.middleware << Event::Middleware::Aimer::DispatcherTarget.new
222
+ @dispatcher.middleware << Event::Middleware::Dispatch.new
223
+ @dispatcher.middleware << Event::Middleware::Translator::MouseClick.new
224
+ end
225
+
226
+ def validate_adapter(adapter)
227
+ # TODO: Raise error if ever set more than once
228
+ raise Error::InvalidAdapter unless adapter.is_a?(Cura::Adapter)
229
+
230
+ adapter
231
+ end
232
+
233
+ def run_event_loop
234
+ @running = true
235
+
236
+ while @running
237
+ update
238
+ draw
239
+ dispatcher.run
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ end
@@ -0,0 +1,40 @@
1
+ module Cura
2
+ module Attributes
3
+
4
+ # Allows an object to have a `parent` and `ancestors`.
5
+ module HasAncestry
6
+
7
+ def initialize(attributes={})
8
+ @ancestors = []
9
+
10
+ super
11
+ end
12
+
13
+ # Get/set the parent of this object.
14
+ # It's not recommended to set this directly as it may break the ancestory chain.
15
+ #
16
+ # @return [Object]
17
+ attr_accessor :parent
18
+
19
+ # Determine if this object has a parent.
20
+ #
21
+ # @return [Boolean]
22
+ def parent?
23
+ !@parent.nil?
24
+ end
25
+
26
+ # Get the ancestors of this object.
27
+ #
28
+ # @return [Array<Object>]
29
+ def ancestors
30
+ if @parent.nil?
31
+ []
32
+ else
33
+ @parent.respond_to?(:ancestors) ? [@parent] + @parent.ancestors : [@parent]
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/application"
3
+
4
+ require "cura/error/invalid_application"
5
+ end
6
+
7
+ module Cura
8
+ module Attributes
9
+
10
+ # Allows an object to belong to a Cura::Application.
11
+ module HasApplication
12
+
13
+ # Get the application of this object.
14
+ #
15
+ # @return [Application]
16
+ attr_reader :application
17
+
18
+ # Set the application of this object.
19
+ #
20
+ # @param [Application] value
21
+ # @return [Application]
22
+ def application=(value)
23
+ raise Error::InvalidApplication unless value.nil? || value.is_a?(Cura::Application)
24
+
25
+ @application = value
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,89 @@
1
+ module Cura
2
+ module Attributes
3
+
4
+ # Adds the `update_attributes` method.
5
+ module HasAttributes # TODO: Aspect::HasAttributes
6
+
7
+ # The class methods to be mixed in when included.
8
+ module ClassMethods
9
+
10
+ def attribute(name, options={}, &block)
11
+ options = options.to_h
12
+
13
+ if options[:query]
14
+ define_method("#{name}?") { instance_variable_get("@#{name}") }
15
+ else
16
+ attr_reader(name)
17
+ end
18
+
19
+ if options[:query]
20
+ define_method("#{name}=") do |value|
21
+ value = instance_exec(value, options, &block) unless block.nil?
22
+
23
+ instance_variable_set("@#{name}", !!value)
24
+ end
25
+ else
26
+ define_method("#{name}=") do |value|
27
+ value = instance_exec(value, options, &block) unless block.nil?
28
+
29
+ instance_variable_set("@#{name}", value)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ class << self
37
+
38
+ def included(base)
39
+ base.extend(ClassMethods)
40
+ end
41
+
42
+ end
43
+
44
+ # Initialize this object by optionally updating attributes with a Hash.
45
+ #
46
+ # @param [#to_h] attributes Attributes to set after initializing.
47
+ def initialize(attributes={})
48
+ update_attributes(attributes)
49
+
50
+ super
51
+ end
52
+
53
+ # Update any attributes on this object.
54
+ #
55
+ # @param [#to_h] attributes
56
+ # @return [Hash] The attributes.
57
+ def update_attributes(attributes={})
58
+ attributes = convert_attributes(attributes)
59
+
60
+ attributes.each { |name, value| send("#{name}=", value) }
61
+ end
62
+
63
+ protected
64
+
65
+ VALID_SIZE_SYMBOLS = [:auto, :inherit]
66
+
67
+ def validate_size_attribute(value)
68
+ if value.is_a?(Symbol)
69
+ raise ArgumentError, "must be one of #{VALID_SIZE_SYMBOLS.join(', ')}" unless VALID_SIZE_SYMBOLS.include?(value)
70
+ else
71
+ value = value.to_i
72
+ value = 0 if value < 0
73
+ end
74
+
75
+ value
76
+ end
77
+
78
+ # Convert the attributes to a Hash and any other conversions that may need to happen.
79
+ #
80
+ # @param [#to_h] attributes
81
+ # @return [Hash] The attributes.
82
+ def convert_attributes(attributes={})
83
+ attributes.to_h
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+ end