cura 0.0.2 → 0.0.3

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +25 -11
  3. data/Gemfile.lock +157 -62
  4. data/Rakefile +71 -18
  5. data/examples/todo_list/bin/todo_list +4 -1
  6. data/examples/todo_list/lib/todo_list/component/list_items.rb +27 -27
  7. data/examples/todo_list/lib/todo_list/component/lists.rb +27 -27
  8. data/lib/cura/application.rb +3 -0
  9. data/lib/cura/attributes/has_children.rb +25 -4
  10. data/lib/cura/attributes/has_colors.rb +7 -3
  11. data/lib/cura/attributes/has_dimensions.rb +1 -1
  12. data/lib/cura/attributes/has_events.rb +1 -1
  13. data/lib/cura/attributes/has_root.rb +8 -3
  14. data/lib/cura/attributes/has_visibility.rb +28 -0
  15. data/lib/cura/color.rb +2 -0
  16. data/lib/cura/component/base.rb +34 -9
  17. data/lib/cura/component/group.rb +19 -2
  18. data/lib/cura/component/listbox.rb +15 -4
  19. data/lib/cura/component/pack.rb +8 -4
  20. data/lib/cura/component.rb +23 -0
  21. data/lib/cura/error/invalid_component.rb +1 -1
  22. data/lib/cura/event/dispatcher.rb +1 -1
  23. data/lib/cura/event/middleware/aimer/target_option.rb +1 -3
  24. data/lib/cura/event/middleware/dispatch.rb +3 -2
  25. data/lib/cura/event/middleware/translator/mouse_click.rb +1 -1
  26. data/lib/cura/key.rb +12 -12
  27. data/lib/cura/version.rb +1 -1
  28. data/spec/spec_helper.rb +0 -1
  29. data/spec/{cura → unit/cura}/attributes/has_ancestry_spec.rb +0 -0
  30. data/spec/{cura → unit/cura}/attributes/has_application_spec.rb +0 -0
  31. data/spec/{cura → unit/cura}/attributes/has_attributes_spec.rb +0 -0
  32. data/spec/{cura → unit/cura}/attributes/has_children_spec.rb +0 -0
  33. data/spec/{cura → unit/cura}/attributes/has_colors_spec.rb +0 -0
  34. data/spec/{cura → unit/cura}/attributes/has_coordinates_spec.rb +0 -0
  35. data/spec/{cura → unit/cura}/attributes/has_dimensions_spec.rb +0 -0
  36. data/spec/{cura → unit/cura}/attributes/has_events_spec.rb +0 -0
  37. data/spec/{cura → unit/cura}/attributes/has_focusability_spec.rb +0 -0
  38. data/spec/{cura → unit/cura}/attributes/has_offsets_spec.rb +0 -0
  39. data/spec/{cura → unit/cura}/attributes/has_orientation_spec.rb +0 -0
  40. data/spec/{cura → unit/cura}/attributes/has_relative_coordinates_spec.rb +0 -0
  41. data/spec/{cura → unit/cura}/attributes/has_side_attributes_spec.rb +0 -0
  42. metadata +43 -51
  43. data/examples/box_model/debug.log +0 -0
  44. data/examples/todo_list/app.log +0 -9
  45. data/examples/todo_list/data.db +0 -0
  46. data/examples/todo_list/debug.log +0 -0
  47. data/examples/todo_list/profile.html +0 -11354
@@ -2,88 +2,88 @@ require "todo_list/component/list"
2
2
 
3
3
  module TodoList
4
4
  module Component
5
-
5
+
6
6
  class Lists < Cura::Component::Pack
7
-
7
+
8
8
  attr_reader :create_list_textbox
9
9
  attr_reader :listbox
10
-
11
-
10
+
11
+
12
12
  def initialize(attributes={})
13
13
  attributes = { fill: true, padding: { top: 1, bottom: 1 } }.merge(attributes)
14
-
14
+
15
15
  super(attributes)
16
-
16
+
17
17
  create_form_pack = Cura::Component::Pack.new(orientation: :horizontal)
18
18
  add_child(create_form_pack)
19
-
19
+
20
20
  @create_list_textbox = Cura::Component::Textbox.new(width: width - 16, margin: { right: 1 })
21
21
  @create_list_textbox.on_event(:key_down, self) { |event, model_list| model_list.create_list if event.name == :enter }
22
22
  create_form_pack.add_child(@create_list_textbox)
23
-
23
+
24
24
  @create_list_button = Cura::Component::Button.new(text: "Create List", padding: { left: 1, right: 1 })
25
25
  @create_list_button.on_event(:click, self) { |_, model_list| model_list.create_list }
26
26
  create_form_pack.add_child(@create_list_button)
27
-
27
+
28
28
  @listbox_header_label = Cura::Component::Label.new(text: "Lists" + " " * (width - 5), bold: true, underline: true, margin: { top: 1 })
29
29
  add_child(@listbox_header_label)
30
-
30
+
31
31
  @listbox = Cura::Component::Listbox.new(width: @width)
32
-
32
+
33
33
  @listbox.on_event(:selected) do
34
34
  application.list_items.list = selected_object unless selected_object.nil?
35
35
  end
36
-
36
+
37
37
  @listbox.on_event(:key_down, self) do |event, model_list|
38
38
  if event.target == self
39
39
  if event.control? && event.name == :D && !selected_object.nil?
40
40
  selected_object.list_items.each(&:destroy)
41
41
  selected_object.destroy
42
-
42
+
43
43
  application.list_items.list = nil
44
44
 
45
45
  previous_selected_index = @selected_index
46
46
  model_list.fill_listbox
47
47
  self.selected_index = [previous_selected_index, count - 1].min
48
48
  end
49
-
49
+
50
50
  if event.control? && event.name == :E
51
51
  selected_child.focus
52
52
  end
53
-
53
+
54
54
  if event.name == :enter
55
55
  application.list_items.listbox.focus
56
56
  end
57
57
  end
58
58
  end
59
-
59
+
60
60
  add_child(@listbox)
61
-
61
+
62
62
  fill_listbox
63
63
  end
64
-
64
+
65
65
  def create_list
66
66
  Model::List.create(text: @create_list_textbox.text)
67
-
67
+
68
68
  fill_listbox
69
-
69
+
70
70
  @create_list_textbox.clear
71
71
  @create_list_textbox.focus
72
-
72
+
73
73
  application.list_items.list = @listbox.selected_object unless @listbox.selected_object.nil?
74
74
  end
75
-
75
+
76
76
  def fill_listbox
77
77
  @listbox.delete_children
78
-
78
+
79
79
  Model::List.all.each do |list|
80
80
  list_component = Component::List.new(listbox: @listbox, model: list, width: @listbox.width)
81
-
82
- @listbox.add_child(list_component, list)
81
+
82
+ @listbox.add_child(list_component, object: list)
83
83
  end
84
84
  end
85
-
85
+
86
86
  end
87
-
87
+
88
88
  end
89
89
  end
@@ -207,6 +207,9 @@ module Cura
207
207
  end
208
208
 
209
209
  # TODO: If a class is given, run .new on it first
210
+ # TODO: Adapter.name(*arguments) which defaults to an underscore'd version of the class constant
211
+ # TODO: Adapter.find_by_name
212
+ # TODO: Use Adapter.find_by_name here to allow passing of a Symbol to #adapter=
210
213
 
211
214
  @adapter.setup
212
215
  end
@@ -1,6 +1,5 @@
1
1
  if Kernel.respond_to?(:require)
2
2
  require "cura/component/base"
3
-
4
3
  require "cura/error/invalid_component"
5
4
  end
6
5
 
@@ -38,10 +37,32 @@ module Cura
38
37
 
39
38
  # Add a child to this group.
40
39
  #
41
- # @param [Component] component
40
+ # If a Hash-like object is given, it must have the `:type` key which will be used to
41
+ # determine which class to initialize. The rest of the Hash will be used to set the
42
+ # attributes of the instance.
43
+ #
44
+ # @param [#to_sym, Component] component_or_type
45
+ # A Symbol representing the child component type or a {Component::Base} instance.
46
+ # When a Symbol is given, a new child component will be initialized of that type. See {Component::Base.type}.
47
+ # @param [#to_h] attributes
48
+ # When component_or_type is a Symbol, then these attributes will be used to initialize the child component.
49
+ # When component_or_type is a {Component::Base}, then these attributes will be used to update the child component.
42
50
  # @return [Component]
43
- def add_child(component)
44
- raise TypeError, "component must be a Cura::Component" unless component.is_a?(Component::Base)
51
+ def add_child(component_or_type, attributes={})
52
+ component = if component_or_type.respond_to?(:to_sym)
53
+ type = component_or_type.to_sym
54
+ component_class = Component.find_by_type(type)
55
+
56
+ raise Error::InvalidComponent if component_class.nil?
57
+
58
+ component_class.new
59
+ else
60
+ raise Error::InvalidComponent unless component_or_type.is_a?(Component::Base)
61
+
62
+ component_or_type
63
+ end
64
+
65
+ component.update_attributes(attributes)
45
66
 
46
67
  @children << component
47
68
 
@@ -28,7 +28,7 @@ module Cura
28
28
  # @method foreground=(value)
29
29
  # Set the foreground color of this object.
30
30
  #
31
- # @param [Color] value
31
+ # @param [Color, #to_sym] value
32
32
  # @return [Color]
33
33
 
34
34
  attribute(:foreground) { |value| validate_color_attribute(value) }
@@ -41,7 +41,7 @@ module Cura
41
41
  # @method background=(value)
42
42
  # Set the background color of this object.
43
43
  #
44
- # @param [Color] value
44
+ # @param [Color, #to_sym] value
45
45
  # @return [Color]
46
46
 
47
47
  attribute(:background) { |value| validate_color_attribute(value) }
@@ -52,7 +52,11 @@ module Cura
52
52
  unless value.is_a?(Cura::Color)
53
53
  value = value.to_sym
54
54
 
55
- raise Error::InvalidColor unless value == :inherit
55
+ if [:black, :white, :red, :green, :blue].include?(value)
56
+ value = Cura::Color.send(value)
57
+ else
58
+ raise Error::InvalidColor unless value == :inherit
59
+ end
56
60
  end
57
61
 
58
62
  value
@@ -16,12 +16,12 @@ module Cura
16
16
  # @method width
17
17
  # Get the width dimension of this object.
18
18
  #
19
- # @param [#to_i] value
20
19
  # @return [Integer]
21
20
 
22
21
  # @method width=(value)
23
22
  # Set the width dimension of this object.
24
23
  #
24
+ # @param [#to_i] value
25
25
  # @return [Integer]
26
26
 
27
27
  attribute(:width) { |value| validate_size_attribute(value) }
@@ -56,7 +56,7 @@ module Cura
56
56
  # Get the event handler for this object.
57
57
  #
58
58
  # @return [Event::Handler]
59
- attr_reader :event_handler
59
+ attr_reader :event_handler # TODO: Rename to #events ?
60
60
 
61
61
  # Register a callback for an event to this instance.
62
62
  #
@@ -40,10 +40,15 @@ module Cura
40
40
 
41
41
  # Add a child to this object's root component.
42
42
  #
43
- # @param [Component] component
43
+ # @param [#to_sym, Component] component_or_type
44
+ # A Symbol representing the child component type or a {Component::Base} instance.
45
+ # When a Symbol is given, a new child component will be initialized of that type. See {Component::Base.type}.
46
+ # @param [#to_h] attributes
47
+ # When component_or_type is a Symbol, then these attributes will be used to initialize the child component.
48
+ # When component_or_type is a {Component::Base}, then these attributes will be used to update the child component.
44
49
  # @return [Component]
45
- def add_child(component)
46
- @root.add_child(component)
50
+ def add_child(component_or_type, attributes={})
51
+ @root.add_child(component_or_type, attributes)
47
52
  end
48
53
 
49
54
  # Add multiple children to this object's root component.
@@ -0,0 +1,28 @@
1
+ require "cura/attributes/has_attributes" if Kernel.respond_to?(:require)
2
+
3
+ module Cura
4
+ module Attributes
5
+ # Adds the `#visible?`, `visible=` methods.
6
+ module HasVisibility
7
+ include HasAttributes
8
+
9
+ def initialize(attributes={})
10
+ @visible = true
11
+
12
+ super
13
+ end
14
+
15
+ # @method visible?
16
+ # Get the visibility.
17
+ #
18
+ # @return [Boolean]
19
+
20
+ # @method visible=
21
+ # Set the visibility.
22
+ #
23
+ # @return [Boolean]
24
+
25
+ attribute(:visible, query: true)
26
+ end
27
+ end
28
+ end
data/lib/cura/color.rb CHANGED
@@ -10,6 +10,8 @@ module Cura
10
10
  include Attributes::HasAttributes
11
11
 
12
12
  class << self
13
+ # TODO: All standard color names
14
+
13
15
  # The default color to be overidden by adapters.
14
16
  # Usually, for TUI's to use the terminal theme's colors.
15
17
  # TODO: Remove.
@@ -6,6 +6,8 @@ if Kernel.respond_to?(:require)
6
6
  require "cura/attributes/has_events"
7
7
  require "cura/attributes/has_offsets"
8
8
  require "cura/attributes/has_relative_coordinates"
9
+ require "cura/attributes/has_visibility"
10
+ require "cura/component"
9
11
  end
10
12
 
11
13
  module Cura
@@ -15,14 +17,35 @@ module Cura
15
17
  # All components use a box model similar to CSS.
16
18
  # Margins, borders, paddings, then content.
17
19
  class Base
20
+ class << self
21
+ # On subclass hook.
22
+ def inherited(subclass)
23
+ Component.all << subclass
24
+ end
25
+
26
+ # The type of this component class.
27
+ #
28
+ # @example
29
+ # Cura::Component::XMLTools::AttributeLabel.type # => :xml_tools_attribute_label
30
+ # @return [Symbol]
31
+ def type # TODO: Helper method for this sort of thing
32
+ @type ||= to_s.gsub(/^Cura::Component::/, "")
33
+ .gsub(/([A-Z][A-Za-z]*)([A-Z][A-Za-z0-9_]*)/, "\\1_\\2")
34
+ .gsub(/::/, "_").downcase.to_sym
35
+ end
36
+ end
37
+
18
38
  include Attributes::HasInitialize
19
39
  include Attributes::HasAttributes
40
+
41
+ include Attributes::HasAncestry
20
42
  include Attributes::HasDimensions
21
43
  include Attributes::HasEvents
22
44
  include Attributes::HasFocusability
23
45
  include Attributes::HasColors
24
46
  include Attributes::HasOffsets
25
47
  include Attributes::HasRelativeCoordinates
48
+ include Attributes::HasVisibility
26
49
 
27
50
  # Get the cursor for this application.
28
51
  # TODO: Delegate something like: def_delegate(:cursor) { application }
@@ -89,13 +112,6 @@ module Cura
89
112
  get_or_inherit_color(:background, Color.white)
90
113
  end
91
114
 
92
- # Instance inspection.
93
- #
94
- # @return [String]
95
- def inspect
96
- "#<#{self.class}:0x#{__id__.to_s(16)} x=#{x} y=#{y} absolute_x=#{absolute_x} absolute_y=#{absolute_y} w=#{width} h=#{height} parent=#{@parent.class}:0x#{@parent.__id__.to_s(16)}>"
97
- end
98
-
99
115
  # Update this component.
100
116
  #
101
117
  # @return [Component]
@@ -107,12 +123,21 @@ module Cura
107
123
  #
108
124
  # @return [Component]
109
125
  def draw
110
- draw_background
111
- draw_border
126
+ if @visible
127
+ draw_background
128
+ draw_border
129
+ end
112
130
 
113
131
  self
114
132
  end
115
133
 
134
+ # Instance inspection.
135
+ #
136
+ # @return [String]
137
+ def inspect
138
+ "#<#{self.class}:0x#{__id__.to_s(16)} x=#{x} y=#{y} absolute_x=#{absolute_x} absolute_y=#{absolute_y} w=#{width} h=#{height} parent=#{@parent.class}:0x#{@parent.__id__.to_s(16)}>"
139
+ end
140
+
116
141
  protected
117
142
 
118
143
  # Draw a point.
@@ -30,11 +30,28 @@ module Cura
30
30
  children.collect { |child| child.y + child.height + child.offsets.height }.max
31
31
  end
32
32
 
33
+ # # Set the parent of this object.
34
+ # # It's not recommended to set this directly as it may break the ancestory chain.
35
+ # #
36
+ # # @param [Object] value
37
+ # # @return [Object]
38
+ # def parent=(value)
39
+ # @parent = value
40
+ # @children.each
41
+ #
42
+ # @parent
43
+ # end
44
+
33
45
  # Add a child to this group and set it's parent to this Group.
34
46
  #
35
- # @param [Component] component
47
+ # @param [#to_sym, Component] component_or_type
48
+ # A Symbol representing the child component type or a {Component::Base} instance.
49
+ # When a Symbol is given, a new child component will be initialized of that type. See {Component::Base.type}.
50
+ # @param [#to_h] attributes
51
+ # When component_or_type is a Symbol, then these attributes will be used to initialize the child component.
52
+ # When component_or_type is a {Component::Base}, then these attributes will be used to update the child component.
36
53
  # @return [Component]
37
- def add_child(component)
54
+ def add_child(component_or_type, attributes={})
38
55
  component = super
39
56
 
40
57
  component.parent = self
@@ -83,11 +83,17 @@ module Cura
83
83
 
84
84
  # Add a child to this group.
85
85
  #
86
- # @param [Component] component
87
- # @param [Object] object An arbitrary object to associate with the added child in this listbox.
86
+ # @param [#to_sym, Component] component_or_type
87
+ # A Symbol representing the child component type or a {Component::Base} instance.
88
+ # When a Symbol is given, a new child component will be initialized of that type. See {Component::Base.type}.
89
+ # @param [#to_h] attributes
90
+ # When component_or_type is a Symbol, then these attributes will be used to initialize the child component.
91
+ # When component_or_type is a {Component::Base}, then these attributes will be used to update the child component.
92
+ # @option attributes [Object] :object An arbitrary object to associate with the added child in this listbox.
88
93
  # @return [Component]
89
- def add_child(component, object=nil)
90
- child = super(component)
94
+ def add_child(component_or_type, attributes={})
95
+ object = attributes.delete(:object)
96
+ child = super
91
97
 
92
98
  @objects << object
93
99
 
@@ -107,6 +113,11 @@ module Cura
107
113
  deleted_child
108
114
  end
109
115
 
116
+ # Get the objects stored.
117
+ #
118
+ # @return [Array]
119
+ attr_reader :objects
120
+
110
121
  # Get the associated object with the child at the given index.
111
122
  #
112
123
  # @param [#to_i] index
@@ -15,7 +15,6 @@ module Cura
15
15
  @fill = false
16
16
  @spacing = 0
17
17
 
18
- # @child_modifiers
19
18
  super
20
19
  end
21
20
 
@@ -39,15 +38,20 @@ module Cura
39
38
 
40
39
  # Add a child to this group.
41
40
  #
42
- # @param [Component] component
43
- # @param [#to_hash, #to_h] options
41
+ # @param [#to_sym, Component] component_or_type
42
+ # A Symbol representing the child component type or a {Component::Base} instance.
43
+ # When a Symbol is given, a new child component will be initialized of that type. See {Component::Base.type}.
44
+ # @param [#to_h] attributes
45
+ # When component_or_type is a Symbol, then these attributes will be used to initialize the child component.
46
+ # When component_or_type is a {Component::Base}, then these attributes will be used to update the child component.
44
47
  # @option options [#to_i] :expand
45
48
  # The new child is to be given extra space. The extra space will be divided evenly between all children that use this option.
46
49
  # @option options [#to_i] :fill
47
50
  # The space given to child by the expand option is actually allocated to child, rather than just padding it.
48
51
  # This parameter has no effect if expand is set to false.
49
52
  # @return [Component]
50
- def add_child(component)
53
+ def add_child(component_or_type, attributes={})
54
+ # TODO: :expand and :fill attributes?
51
55
  child = super
52
56
 
53
57
  pack_children
@@ -0,0 +1,23 @@
1
+ module Cura
2
+ # The container module for components.
3
+ module Component
4
+ class << self
5
+ # All {Component::Base} subclasses.
6
+ #
7
+ # @return [<Class>]
8
+ def all
9
+ @all ||= []
10
+ end
11
+
12
+ # Find a {Component::Base} subclass by it's type.
13
+ #
14
+ # @param [#to_sym] value
15
+ # @return [nil, Class]
16
+ def find_by_type(value)
17
+ value = value.to_sym
18
+
19
+ all.find { |component_class| component_class.type == value }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -5,7 +5,7 @@ module Cura
5
5
  # Raised when a component is invalid.
6
6
  class InvalidComponent < Base
7
7
  def to_s
8
- "must be a Cura::Component::Base"
8
+ "invalid component"
9
9
  end
10
10
  end
11
11
  end
@@ -96,7 +96,7 @@ module Cura
96
96
  @application.adapter.peek_event(milliseconds.to_i)
97
97
  end
98
98
 
99
- # Dispatch an event to the target or application, if the target is nil.
99
+ # Send the event through the middleware stack and dispatch all events on the queue.
100
100
  #
101
101
  # @param [#to_sym] event The name of the event class to create an instance of or an event instance.
102
102
  # @param [#to_hash, #to_h] options The options to pass through the middleware.
@@ -6,15 +6,13 @@ module Cura
6
6
  module Aimer
7
7
  # Sets the event's target to the component passed by an optional :target option.
8
8
  class TargetOption < Base
9
+ # @method call
9
10
  # Call this middleware.
10
11
  #
11
12
  # @param [#to_h] options
12
13
  # @option options [Event::Dispatcher] :dispatcher
13
14
  # @option options [Event::Base] :event
14
15
  # @option options [Attributes::HasEvents] :target The optional target of the event.
15
- def call(options={})
16
- super # Only here for documentation
17
- end
18
16
 
19
17
  protected
20
18
 
@@ -1,9 +1,10 @@
1
1
  module Cura
2
2
  module Event
3
3
  module Middleware
4
- # Dispatches the event.
4
+ # Adds the event to the dispatch queue.
5
+ # Should be the very last middleware in the chain.
5
6
  class Dispatch < Base
6
- # Dispatch the event.
7
+ # Add the event to the dispatch queue.
7
8
  #
8
9
  # @param [#to_h] options
9
10
  # @option options [Event::Base] :event
@@ -10,7 +10,7 @@ module Cura
10
10
  # Translates MouseDown and MouseUp events into a MouseClick event.
11
11
  class MouseClick < Base
12
12
  def initialize
13
- @last_mouse_down_at = Time.now
13
+ @last_mouse_down_at = Time.now # TODO: This is not a great solution. If/when events are threaded, this will be bad.
14
14
  end
15
15
 
16
16
  # Call this middleware.
data/lib/cura/key.rb CHANGED
@@ -197,18 +197,18 @@ module Cura
197
197
  mute: nil,
198
198
  non_us_backslash: nil,
199
199
  non_us_hash: nil,
200
- "0": "0",
201
- "00": "00",
202
- "000": "000",
203
- "1": "1",
204
- "2": "2",
205
- "3": "3",
206
- "4": "4",
207
- "5": "5",
208
- "6": "6",
209
- "7": "7",
210
- "8": "8",
211
- "9": "9",
200
+ "0".to_sym => "0",
201
+ "00".to_sym => "00",
202
+ "000".to_sym => "000",
203
+ "1".to_sym => "1",
204
+ "2".to_sym => "2",
205
+ "3".to_sym => "3",
206
+ "4".to_sym => "4",
207
+ "5".to_sym => "5",
208
+ "6".to_sym => "6",
209
+ "7".to_sym => "7",
210
+ "8".to_sym => "8",
211
+ "9".to_sym => "9",
212
212
  numlock_clear: nil,
213
213
  numpad_0: "0",
214
214
  numpad_1: "1",
data/lib/cura/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # An adaptable component library for creating graphical and text-based user interfaces.
2
2
  module Cura
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require "simplecov"
2
- SimpleCov.start
3
2
 
4
3
  RSpec.configure do |config|
5
4
  config.expect_with :rspec do |expectations|