cura 0.0.1

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 (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,118 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/component/label"
3
+ require "cura/key"
4
+ end
5
+
6
+ module Cura
7
+ module Component
8
+
9
+ # A component containing editable text.
10
+ class Textbox < Label
11
+
12
+ on_event(:focus) do
13
+ set_cursor_position
14
+
15
+ cursor.show
16
+ end
17
+
18
+ on_event(:unfocus) { cursor.hide }
19
+
20
+ on_event(:key_down) do |event|
21
+ if event.target == self
22
+ if event.name == :backspace
23
+ self.text = text[0..-2] # TODO: Should delete the charactor before the cursor when it is movable
24
+ elsif event.name == :space
25
+ text << " "
26
+ # elsif event.name == :enter # TODO: if multiline?
27
+ # self.text << "\n"
28
+ elsif event.printable?
29
+ text << event.character
30
+ end
31
+
32
+ set_cursor_position
33
+ end
34
+ end
35
+
36
+ def initialize(attributes={})
37
+ @focusable = true
38
+ @foreground = Cura::Color.black
39
+ @background = Cura::Color.white
40
+
41
+ super
42
+
43
+ # TODO
44
+ # @width = 1 if @width != :auto && @width < 1
45
+ # @height = 1 if @height != :auto && @height < 1
46
+ end
47
+
48
+ # Clear all characters within this textbox.
49
+ #
50
+ # @return [Textbox]
51
+ def clear
52
+ @text = ""
53
+
54
+ set_cursor_position
55
+
56
+ self
57
+ end
58
+
59
+ # Get the mask character for this textbox.
60
+ #
61
+ # @return [String]
62
+ attr_reader :mask_character
63
+
64
+ # Set the mask character for this textbox.
65
+ # Set to anything for a "password" textbox. Only the first character of whatever is given is used.
66
+ #
67
+ # @param [#to_s] value
68
+ # @return [String]
69
+ def mask_character=(value)
70
+ value = value.to_s.strip[0]
71
+ value = nil if value.empty?
72
+
73
+ @mask_character = value
74
+ end
75
+
76
+ # Set the width of this textbox.
77
+ #
78
+ # @param [#to_i] value
79
+ # @return [Integer]
80
+ def width=(value)
81
+ super
82
+
83
+ @width = 1 if @width < 1
84
+ end
85
+
86
+ # Set the height of this textbox.
87
+ #
88
+ # @param [#to_i] value
89
+ # @return [Integer]
90
+ def height=(value)
91
+ super
92
+
93
+ @height = 1 if @height < 1
94
+ end
95
+
96
+ protected
97
+
98
+ def text_to_draw
99
+ return text if text.length <= width
100
+
101
+ focused? ? text[-width..-1] : text[0...width]
102
+ end
103
+
104
+ def character_to_draw(character)
105
+ @mask_character.nil? ? character : @mask_character
106
+ end
107
+
108
+ def set_cursor_position
109
+ last_line_length = lines.last.nil? ? 0 : lines.last.length
110
+
111
+ cursor.x = absolute_x + offsets.left + (text.length < width ? last_line_length : width - 1)
112
+ cursor.y = absolute_y + offsets.top + text_height - 1
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,77 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_initialize"
3
+ require "cura/attributes/has_application"
4
+ require "cura/attributes/has_coordinates"
5
+ end
6
+
7
+ module Cura
8
+
9
+ # The text cursor controller.
10
+ #
11
+ # Should only ever have one single Cursor instance at one time.
12
+ # TODO: Rename Cursor::Text, need Cursor::Mouse
13
+ class Cursor
14
+
15
+ include Attributes::HasInitialize
16
+ include Attributes::HasApplication
17
+ include Attributes::HasCoordinates
18
+
19
+ def initialize(attributes={})
20
+ @hidden = true
21
+
22
+ super
23
+
24
+ raise ArgumentError, "application must be set" if application.nil?
25
+ end
26
+
27
+ # Check if the cursor is hidden.
28
+ #
29
+ # @return [Boolean]
30
+ def hidden?
31
+ !!@hidden
32
+ end
33
+
34
+ # Set if the cursor is hidden.
35
+ #
36
+ # @param [Boolean] value
37
+ # @return [Boolean]
38
+ def hidden=(value)
39
+ value = !!value
40
+
41
+ @hidden = value
42
+ end
43
+
44
+ # Show the cursor.
45
+ #
46
+ # @return [Cursor]
47
+ def show
48
+ @hidden = false
49
+
50
+ self
51
+ end
52
+
53
+ # Hide the cursor.
54
+ #
55
+ # @return [Cursor]
56
+ def hide
57
+ @hidden = true
58
+
59
+ self
60
+ end
61
+
62
+ # Draw (set) the cursor.
63
+ #
64
+ # @return [Cursor]
65
+ def update # TODO: Refactor for speed, this can't be effecient
66
+ if @hidden
67
+ application.adapter.hide_cursor
68
+ else
69
+ application.adapter.set_cursor(@x, @y)
70
+ end
71
+
72
+ self
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,10 @@
1
+ module Cura
2
+ module Error
3
+
4
+ # The base class for errors.
5
+ class Base < StandardError
6
+
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/error/base"
3
+ end
4
+
5
+ module Cura
6
+ module Error
7
+
8
+ # Raised when an adapter is invalid.
9
+ class InvalidAdapter < Base
10
+
11
+ def to_s
12
+ "The adapter is invalid." # TODO: Better message
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/error/base"
3
+ end
4
+
5
+ module Cura
6
+ module Error
7
+
8
+ # Raised when an application is invalid.
9
+ class InvalidApplication < Base
10
+
11
+ def to_s
12
+ "must nil or be a Cura::Application"
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/error/base"
3
+ end
4
+
5
+ module Cura
6
+ module Error
7
+
8
+ # Raised when a color is invalid.
9
+ class InvalidColor < Base
10
+
11
+ def to_s
12
+ "must be a Cura::Color or :inherit"
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/error/base"
3
+ end
4
+
5
+ module Cura
6
+ module Error
7
+
8
+ # Raised when a component is invalid.
9
+ class InvalidComponent < Base
10
+
11
+ def to_s
12
+ "must be a Cura::Component::Base"
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/error/base"
3
+ end
4
+
5
+ module Cura
6
+ module Error
7
+
8
+ # Raised when middleware is invalid.
9
+ class InvalidMiddleware < Base
10
+
11
+ def to_s
12
+ "must respond to #call."
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ module Cura
2
+
3
+ # The container for Event::Base and it's subclasses.
4
+ module Event
5
+ class << self
6
+
7
+ # Get all Event::Base subclasses.
8
+ #
9
+ # @return [Array<Class>]
10
+ def all
11
+ @all ||= []
12
+ end
13
+
14
+ # Find an Event::Base subclass by it's name.
15
+ #
16
+ # @param [#to_sym] name The name of the event. For example, `SomeAction` would be `:some_action`.
17
+ # @return [nil, Class] The Event::Base subclass.
18
+ def find_by_name(name)
19
+ name = name.to_sym
20
+
21
+ all.find { |event_class| event_class.name == name }
22
+ end
23
+
24
+ # Initialize an Event::Base subclass by it's name.
25
+ #
26
+ # @param [#to_sym] name The name of the event class.
27
+ def new_from_name(name, attributes={})
28
+ # TODO: name should be a string formatted like so 'mouse:button:down' which would correspond to Cura::Event::Mouse::Button::Down
29
+ event_class = find_by_name(name)
30
+ raise ArgumentError, "Unknown event name '#{name}'" if event_class.nil?
31
+
32
+ event_class.new(attributes)
33
+ end
34
+
35
+ end # << self
36
+ end
37
+
38
+ end
@@ -0,0 +1,108 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_initialize"
3
+ require "cura/attributes/has_attributes"
4
+ require "cura/attributes/has_events"
5
+
6
+ require "cura/event"
7
+ end
8
+
9
+ module Cura
10
+ module Event
11
+
12
+ # The base class for all events.
13
+ class Base
14
+
15
+ class << self
16
+
17
+ # Get the name of this class as a symbol.
18
+ # For example, `SomeAction` would be `:some_action`.
19
+ #
20
+ # @return [Symbol]
21
+ def name
22
+ # Note: 1.3 times faster but relys on Regexp and is the only usage of regexp throughout cura.
23
+ # Using non regexp version until multiple usages of regexp occur within cura.
24
+ # to_s.split(/::/).last.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
25
+
26
+ # Note: MRuby does not have a #chars method so this is now 2.6 times slower instead of 1.3
27
+ caps = ("A".."Z")
28
+ index = 0
29
+ to_s.split("::").last.split("").each_with_object("") { |char, memo|
30
+ memo << "_" if index > 0 && caps.include?(char)
31
+ memo << char
32
+ index += 1
33
+ }.downcase.to_sym
34
+ end
35
+
36
+ # Add the subclass to `Event.all`, when inherited.
37
+ def inherited(subclass)
38
+ Event.all << subclass
39
+ end
40
+
41
+ end # << self
42
+
43
+ include Attributes::HasInitialize
44
+ include Attributes::HasAttributes
45
+
46
+ def initialize(attributes={})
47
+ @created_at = Time.now
48
+
49
+ super
50
+ end
51
+
52
+ # Get the time this event was created.
53
+ #
54
+ # @return [Time]
55
+ attr_reader :created_at
56
+
57
+ # Get the target this event was dispatched to.
58
+ # TODO: Rename to source.
59
+ # The source is the component the event was originally sent to.
60
+ # The target is the component the event is currently being handled by. <- Needed?
61
+ #
62
+ # @return [Cura::Attributes::HasEvents]
63
+ attr_reader :target
64
+
65
+ # Set the target this event was dispatched to.
66
+ #
67
+ # @param [Cura::Attributes::HasEvents] value
68
+ # @return [Cura::Attributes::HasEvents]
69
+ def target=(value)
70
+ raise TypeError, "target must be a Cura::Attributes::HasEvents" unless value.is_a?(Cura::Attributes::HasEvents) # TODO: Error::Event::InvalidTarget
71
+
72
+ @target = value
73
+ end
74
+
75
+ # Get this event as a Hash.
76
+ #
77
+ # @return [Hash]
78
+ def to_h
79
+ { name: self.class.name }
80
+ end
81
+
82
+ # Check if something is equivalent to this event.
83
+ #
84
+ # @param [Object] other The object to check equivalence with.
85
+ # @return [Boolean]
86
+ def ==(other)
87
+ # TODO: Below is needed?
88
+ # object_equivalence = super
89
+ # return true if object_equivalence
90
+
91
+ other = other.to_h if other.respond_to?(:to_h)
92
+
93
+ other == to_h
94
+ end
95
+
96
+ # Dispatches this event directly to it's target.
97
+ #
98
+ # @return [Event::Base] This event.
99
+ def dispatch
100
+ target.event_handler.handle(self)
101
+
102
+ self
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end