cura 0.0.1 → 0.0.2

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -21
  3. data/cura.gemspec +1 -1
  4. data/examples/hello_world/lib/hello_world.rb +10 -10
  5. data/examples/mruby-examples/mrbgem.rake +5 -6
  6. data/examples/todo_list/data.db +0 -0
  7. data/examples/todo_list/lib/todo_list/application.rb +24 -18
  8. data/lib/cura/adapter.rb +13 -20
  9. data/lib/cura/application.rb +47 -51
  10. data/lib/cura/attributes/has_ancestry.rb +4 -8
  11. data/lib/cura/attributes/has_application.rb +3 -7
  12. data/lib/cura/attributes/has_attributes.rb +1 -9
  13. data/lib/cura/attributes/has_children.rb +14 -20
  14. data/lib/cura/attributes/has_colors.rb +14 -18
  15. data/lib/cura/attributes/has_coordinates.rb +9 -15
  16. data/lib/cura/attributes/has_dimensions.rb +12 -18
  17. data/lib/cura/attributes/has_events.rb +10 -18
  18. data/lib/cura/attributes/has_focusability.rb +5 -11
  19. data/lib/cura/attributes/has_initialize.rb +1 -5
  20. data/lib/cura/attributes/has_offsets.rb +16 -20
  21. data/lib/cura/attributes/has_orientation.rb +12 -18
  22. data/lib/cura/attributes/has_relative_coordinates.rb +4 -8
  23. data/lib/cura/attributes/has_root.rb +18 -22
  24. data/lib/cura/attributes/has_side_attributes.rb +18 -24
  25. data/lib/cura/attributes/has_windows.rb +13 -19
  26. data/lib/cura/borders.rb +0 -4
  27. data/lib/cura/color.rb +84 -91
  28. data/lib/cura/component/base.rb +29 -33
  29. data/lib/cura/component/button.rb +10 -16
  30. data/lib/cura/component/group.rb +14 -18
  31. data/lib/cura/component/label.rb +44 -48
  32. data/lib/cura/component/listbox.rb +24 -28
  33. data/lib/cura/component/pack.rb +14 -18
  34. data/lib/cura/component/scrollbar.rb +41 -45
  35. data/lib/cura/component/textbox.rb +21 -25
  36. data/lib/cura/cursor.rb +15 -23
  37. data/lib/cura/error/base.rb +0 -3
  38. data/lib/cura/error/invalid_adapter.rb +1 -7
  39. data/lib/cura/error/invalid_application.rb +1 -7
  40. data/lib/cura/error/invalid_color.rb +1 -7
  41. data/lib/cura/error/invalid_component.rb +1 -7
  42. data/lib/cura/error/invalid_middleware.rb +1 -7
  43. data/lib/cura/event.rb +4 -8
  44. data/lib/cura/event/base.rb +17 -24
  45. data/lib/cura/event/click.rb +1 -6
  46. data/lib/cura/event/dispatcher.rb +20 -26
  47. data/lib/cura/event/focus.rb +1 -6
  48. data/lib/cura/event/handler.rb +16 -24
  49. data/lib/cura/event/key_down.rb +11 -17
  50. data/lib/cura/event/middleware/aimer/base.rb +4 -10
  51. data/lib/cura/event/middleware/aimer/dispatcher_target.rb +2 -8
  52. data/lib/cura/event/middleware/aimer/mouse_focus.rb +6 -11
  53. data/lib/cura/event/middleware/aimer/target_option.rb +4 -10
  54. data/lib/cura/event/middleware/base.rb +0 -4
  55. data/lib/cura/event/middleware/dispatch.rb +0 -4
  56. data/lib/cura/event/middleware/translator/base.rb +4 -10
  57. data/lib/cura/event/middleware/translator/mouse_click.rb +4 -8
  58. data/lib/cura/event/mouse.rb +5 -11
  59. data/lib/cura/event/mouse_button.rb +21 -27
  60. data/lib/cura/event/mouse_wheel_down.rb +1 -6
  61. data/lib/cura/event/mouse_wheel_up.rb +1 -6
  62. data/lib/cura/event/resize.rb +0 -4
  63. data/lib/cura/event/selected.rb +1 -6
  64. data/lib/cura/event/unfocus.rb +1 -6
  65. data/lib/cura/focus_controller.rb +19 -23
  66. data/lib/cura/key.rb +277 -283
  67. data/lib/cura/margins.rb +0 -4
  68. data/lib/cura/offsets.rb +14 -18
  69. data/lib/cura/padding.rb +0 -4
  70. data/lib/cura/pencil.rb +3 -7
  71. data/lib/cura/version.rb +1 -3
  72. data/lib/cura/window.rb +11 -16
  73. data/spec/cura/attributes/has_ancestry_spec.rb +39 -39
  74. data/spec/cura/attributes/has_application_spec.rb +20 -20
  75. data/spec/cura/attributes/has_attributes_spec.rb +26 -26
  76. data/spec/cura/attributes/has_children_spec.rb +54 -54
  77. data/spec/cura/attributes/has_colors_spec.rb +4 -4
  78. data/spec/cura/attributes/has_coordinates_spec.rb +4 -4
  79. data/spec/cura/attributes/has_dimensions_spec.rb +4 -4
  80. data/spec/cura/attributes/has_events_spec.rb +4 -4
  81. data/spec/cura/attributes/has_focusability_spec.rb +18 -18
  82. data/spec/cura/attributes/has_offsets_spec.rb +4 -4
  83. data/spec/cura/attributes/has_orientation_spec.rb +38 -38
  84. data/spec/cura/attributes/has_relative_coordinates_spec.rb +4 -4
  85. data/spec/cura/attributes/has_side_attributes_spec.rb +4 -4
  86. data/spec/spec_helper.rb +1 -1
  87. data/spec/support/shared_examples_for_attributes.rb +41 -41
  88. metadata +1 -1
@@ -1,14 +1,9 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/event/base"
3
- end
1
+ require "cura/event/base" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
-
8
5
  # Dispatched when a component is clicked.
9
6
  class Click < Base
10
-
11
7
  end
12
-
13
8
  end
14
9
  end
@@ -3,57 +3,53 @@ if Kernel.respond_to?(:require)
3
3
  require "cura/attributes/has_attributes"
4
4
  require "cura/attributes/has_application"
5
5
  require "cura/attributes/has_events"
6
-
7
6
  require "cura/event/base"
8
-
9
7
  require "cura/error/invalid_middleware"
10
8
  end
11
9
 
12
10
  module Cura
13
11
  module Event
14
-
15
12
  # Polls or peeks for events since the last execution and dispatches them to the appropriate component.
16
13
  class Dispatcher
17
-
18
14
  include Attributes::HasInitialize
19
15
  include Attributes::HasAttributes
20
16
  include Attributes::HasApplication
21
-
17
+
22
18
  def initialize(attributes={})
23
19
  super
24
-
20
+
25
21
  raise ArgumentError, "application must be set" if @application.nil?
26
-
22
+
27
23
  @wait_time = 100
28
24
  @target = @application if @target.nil?
29
25
  @middleware = []
30
26
  end
31
-
27
+
32
28
  # @method wait_time
33
29
  # Get the time to wait for events in milliseconds in the run loop.
34
30
  #
35
31
  # @return [Integer]
36
-
32
+
37
33
  # @method wait_time=(value)
38
34
  # Set the time to wait for events in milliseconds in the run loop.
39
35
  # Set to 0 to wait forever (poll instead of peek).
40
36
  #
41
37
  # @param [#to_i] value
42
38
  # @return [Integer]
43
-
39
+
44
40
  attribute(:wait_time) do |value|
45
41
  value = value.to_i
46
42
  value = 0 if value < 0
47
-
43
+
48
44
  value
49
45
  end
50
-
46
+
51
47
  # @method target
52
48
  # Get the object with an event handler to dispatch events to.
53
49
  #
54
50
  # @return [Cura::Attributes::HasEvents]
55
51
  attr_reader :target # TODO: use .attribute() { |value| ... }
56
-
52
+
57
53
  # @method target=(value)
58
54
  # Set the object with an event handler to dispatch events to.
59
55
  # Setting to nil will automatially set the target to the application.
@@ -62,36 +58,36 @@ module Cura
62
58
  # @return [Cura::Attributes::HasEvents]
63
59
  def target=(value)
64
60
  raise TypeError, "target must be a Cura::Attributes::HasEvents or nil" unless value.nil? || value.is_a?(Attributes::HasEvents)
65
-
61
+
66
62
  dispatch_event(:unfocus)
67
63
  @target = value.nil? ? @application : value
68
64
  dispatch_event(:focus)
69
-
65
+
70
66
  value
71
67
  end
72
-
68
+
73
69
  # The middleware stack which an event will pass through before being dispatched.
74
70
  # Middleware must be an object responding to #call.
75
71
  #
76
72
  # @return [Array]
77
73
  attr_reader :middleware
78
-
74
+
79
75
  # Poll or peek for events and dispatch it if one was found.
80
76
  #
81
77
  # @return [Event::Dispatcher]
82
78
  def run
83
79
  event = @wait_time == 0 ? poll : peek(@wait_time)
84
-
80
+
85
81
  dispatch_event(event) unless event.nil?
86
82
  end
87
-
83
+
88
84
  # Wait forever for an event.
89
85
  #
90
86
  # @return [Event::Base]
91
87
  def poll
92
88
  @application.adapter.poll_event
93
89
  end
94
-
90
+
95
91
  # Wait a set amount of time for an event.
96
92
  #
97
93
  # @param [#to_i] milliseconds The amount of time to wait in milliseconds.
@@ -99,7 +95,7 @@ module Cura
99
95
  def peek(milliseconds=100)
100
96
  @application.adapter.peek_event(milliseconds.to_i)
101
97
  end
102
-
98
+
103
99
  # Dispatch an event to the target or application, if the target is nil.
104
100
  #
105
101
  # @param [#to_sym] event The name of the event class to create an instance of or an event instance.
@@ -108,15 +104,13 @@ module Cura
108
104
  def dispatch_event(event, options={})
109
105
  event = Event.new_from_name(event, options) if event.respond_to?(:to_sym)
110
106
  raise TypeError, "event must be an Event::Base" unless event.is_a?(Event::Base)
111
-
107
+
112
108
  options = { dispatcher: self, event: event, dispatch_queue: [] }.merge(options.to_h)
113
-
109
+
114
110
  @middleware.each { |middleware| middleware.call(options) }
115
-
111
+
116
112
  options[:dispatch_queue].each(&:dispatch)
117
113
  end
118
-
119
114
  end
120
-
121
115
  end
122
116
  end
@@ -1,14 +1,9 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/event/base"
3
- end
1
+ require "cura/event/base" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
-
8
5
  # Dispatched when a component is focused.
9
6
  class Focus < Base
10
-
11
7
  end
12
-
13
8
  end
14
9
  end
@@ -1,74 +1,66 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/attributes/has_events"
3
- end
1
+ require "cura/attributes/has_events" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
-
8
5
  # The event handler.
9
- # Each {Cura::Component} as well as several other class's instances have an instance of this handler.
6
+ # Each {Cura::Component} as well as several other class's instances have an instance of this handler.
10
7
  # The handler can have multiple callbacks defined for an arbitrary event name.
11
8
  class Handler
12
-
13
9
  # @param [Cura::Attributes::HasEvents] host The object this handler is attached to.
14
10
  def initialize(host)
15
11
  raise TypeError, "host must be a Cura::Attributes::HasEvents" unless host.is_a?(Cura::Attributes::HasEvents)
16
-
12
+
17
13
  @host = host
18
14
  @callbacks = { default: [] }
19
15
  end
20
-
16
+
21
17
  # Get the object this handler is attached to.
22
- #
18
+ #
23
19
  # @return [Object]
24
20
  attr_reader :host
25
-
21
+
26
22
  # The callbacks defined on this handler.
27
23
  # Key is the event name and the value is an Array of Proc instances.
28
- #
24
+ #
29
25
  # @return [Hash<Symbol,Array>]
30
26
  attr_reader :callbacks
31
-
27
+
32
28
  # Add a callback to the event chain.
33
29
  # The first registered callback will be the first one called (FIFO).
34
30
  # If no event_name is given, the callback is registered to the `:default` name, which are called before all others.
35
31
  def register(event_name=:default, *arguments, &block)
36
32
  (@callbacks[event_name] ||= []) << { block: block, arguments: arguments }
37
33
  end
38
-
34
+
39
35
  # Run all callbacks registered on this instance for the given event.
40
36
  # The event object is given as a block argument to the callbacks.
41
37
  # TODO: These should be able to break the callback chain by returning false in the callback (which would also break the delegation chain).
42
38
  # TODO: The event should be delegated to the host's #parent if there are no callbacks registered for it, if it responds to #parent, and it's not nil.
43
39
  def handle(event)
44
40
  callbacks = @callbacks[:default] + @callbacks[event.class.name].to_a
45
-
41
+
46
42
  chain_broken = false
47
43
  callbacks.each do |callback|
48
-
49
44
  result = host.instance_exec(event, *callback[:arguments], &callback[:block])
50
-
45
+
51
46
  # TODO: Optional event consumption
52
47
  if result == false
53
- # chain_broken = true # TODO TODO TODO TODO TODO
54
-
48
+ # chain_broken = true # TODO TODO TODO TODO TODO
49
+
55
50
  break
56
51
  end
57
-
58
52
  end
59
-
53
+
60
54
  delegate_event(event) unless chain_broken
61
55
  end
62
-
56
+
63
57
  protected
64
-
58
+
65
59
  # Propagate the event to the host's applicable #parent or #application.
66
60
  # TODO: Why is the handler responsible for propagation? Should the component or a Event::Propagator be responsible?
67
61
  def delegate_event(event)
68
62
  host.parent.event_handler.handle(event) if host.respond_to?(:parent) && host.parent.respond_to?(:event_handler)
69
63
  end
70
-
71
64
  end
72
-
73
65
  end
74
66
  end
@@ -1,51 +1,47 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/event/base"
3
- end
1
+ require "cura/event/base" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
-
8
5
  # Dispatched when a key's state changes from up to down.
9
6
  class KeyDown < Base
10
-
11
7
  def initialize(attributes={})
12
8
  @control = false
13
-
9
+
14
10
  super
15
-
11
+
16
12
  raise ArgumentError, "name must be set" if @name.nil?
17
13
  end
18
-
14
+
19
15
  # Get whether the key was pressed while holding the control key.
20
16
  #
21
17
  # @return [Boolean]
22
18
  def control?
23
19
  @control
24
20
  end
25
-
21
+
26
22
  # Get the key name.
27
23
  #
28
24
  # @return [Integer]
29
25
  attr_reader :name
30
-
26
+
31
27
  # Get whether the key is printable.
32
28
  #
33
29
  # @return [Boolean]
34
30
  def printable?
35
31
  return false if @control
36
-
32
+
37
33
  Key.name_is_printable?(@name)
38
34
  end
39
-
35
+
40
36
  # Get the printable character for the key.
41
37
  #
42
38
  # @return [nil, String]
43
39
  def character
44
40
  Key.character_from_name(@name)
45
41
  end
46
-
42
+
47
43
  protected
48
-
44
+
49
45
  # Set if the key was pressed while holding the control key.
50
46
  #
51
47
  # @param [Boolean] value
@@ -53,7 +49,7 @@ module Cura
53
49
  def control=(value)
54
50
  @control = !!value
55
51
  end
56
-
52
+
57
53
  # Set the key name.
58
54
  #
59
55
  # @param [#to_sym] value
@@ -61,8 +57,6 @@ module Cura
61
57
  def name=(value)
62
58
  @name = value.to_sym
63
59
  end
64
-
65
60
  end
66
-
67
61
  end
68
62
  end
@@ -1,15 +1,11 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/event/middleware/base"
3
- end
1
+ require "cura/event/middleware/base" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
5
  module Middleware
8
6
  module Aimer
9
-
10
7
  # The base class for event middleware which set's a target, if needed.
11
8
  class Base
12
-
13
9
  # Call this middleware.
14
10
  #
15
11
  # @param [#to_h] options
@@ -19,19 +15,17 @@ module Cura
19
15
  def call(options={})
20
16
  set_target(options) if should_aim?(options)
21
17
  end
22
-
18
+
23
19
  protected
24
-
20
+
25
21
  def should_aim?(options={})
26
22
  options[:event].target.nil?
27
23
  end
28
-
24
+
29
25
  def set_target(_options={})
30
26
  # Does nothing on purpose
31
27
  end
32
-
33
28
  end
34
-
35
29
  end
36
30
  end
37
31
  end
@@ -1,23 +1,17 @@
1
- if Kernel.respond_to?(:require)
2
- require "cura/event/middleware/aimer/base"
3
- end
1
+ require "cura/event/middleware/aimer/base" if Kernel.respond_to?(:require)
4
2
 
5
3
  module Cura
6
4
  module Event
7
5
  module Middleware
8
6
  module Aimer
9
-
10
7
  # Sets the event's target to the dispatcher's target, if it isn't already set.
11
8
  class DispatcherTarget < Base
12
-
13
9
  protected
14
-
10
+
15
11
  def set_target(options={})
16
12
  options[:event].target ||= options[:dispatcher].target
17
13
  end
18
-
19
14
  end
20
-
21
15
  end
22
16
  end
23
17
  end
@@ -1,6 +1,5 @@
1
1
  if Kernel.respond_to?(:require)
2
2
  require "cura/event/mouse_button"
3
-
4
3
  require "cura/event/middleware/aimer/base"
5
4
  end
6
5
 
@@ -8,22 +7,20 @@ module Cura
8
7
  module Event
9
8
  module Middleware
10
9
  module Aimer
11
-
12
10
  # Sets the dispatcher's target to the component underneath the cursor on mouse button events.
13
11
  class MouseFocus < Base
14
-
15
12
  protected
16
-
13
+
17
14
  def should_aim?(options={})
18
15
  options[:event].is_a?(Event::MouseButton) && options[:event].down?
19
16
  end
20
-
17
+
21
18
  def set_target(options={})
22
19
  component = nearest_focusable_ancestor(top_most_component_at(options))
23
-
20
+
24
21
  options[:dispatcher].target = component unless options[:dispatcher].target == component
25
22
  end
26
-
23
+
27
24
  # TODO: Some kind of hit tester class that initializes with a Window to get it's root element and determines
28
25
  # if a set of coordinates are within the bounds of which component in the view tree.
29
26
  def top_most_component_at(options={})
@@ -31,17 +28,15 @@ module Cura
31
28
  window = options[:dispatcher].application.windows.first # TODO: Should be getting the screen coordinates from the event, not relevent to the window
32
29
  window.children(true).reverse.find { |child| child.contains_coordinates?(x: options[:event].x, y: options[:event].y) }
33
30
  end
34
-
31
+
35
32
  def nearest_focusable_ancestor(component)
36
33
  return nil unless component.respond_to?(:focusable?)
37
34
  return component if component.focusable?
38
35
  return nil unless component.respond_to?(:parent)
39
-
36
+
40
37
  nearest_focusable_ancestor(component.parent)
41
38
  end
42
-
43
39
  end
44
-
45
40
  end
46
41
  end
47
42
  end