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,152 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/component/pack"
3
+ require "cura/key"
4
+ end
5
+
6
+ module Cura
7
+ module Component
8
+
9
+ # A component containing a selectable list of components.
10
+ class Listbox < Pack
11
+
12
+ on_event(:focus) do |event|
13
+ if event.target == self
14
+ set_cursor_position
15
+ cursor.show
16
+ end
17
+ end
18
+
19
+ on_event(:unfocus) do |event|
20
+ cursor.hide if event.target == self
21
+ end
22
+
23
+ on_event(:key_down) do |event|
24
+ if event.target == self
25
+ self.selected_index -= 1 if event.name == :up
26
+ self.selected_index += 1 if event.name == :down
27
+ end
28
+ end
29
+
30
+ on_event(:mouse_button) do |event|
31
+ if event.target == self && event.down?
32
+ child = @children.find { |child| child.contains_coordinates?(x: event.x, y: event.y) }
33
+
34
+ self.selected_index = @children.index(child) unless child.nil?
35
+ end
36
+ end
37
+
38
+ on_event(:selected) do |event|
39
+ set_cursor_position if event.target == self && focused?
40
+ end
41
+
42
+ def initialize(attributes={})
43
+ @focusable = true
44
+ @loopable = true
45
+ @selected_index = 0
46
+ @objects = []
47
+
48
+ super
49
+ end
50
+
51
+ # Get the currently selected item's index.
52
+ # Returns `nil` is nothing is selected.
53
+ #
54
+ # @return [nil, Integer]
55
+ attr_reader :selected_index
56
+
57
+ # Set the currently selected item's index.
58
+ # Set to `nil` if nothing is selected.
59
+ #
60
+ # @param [nil, #to_i] value
61
+ # @return [nil, Integer]
62
+ def selected_index=(value)
63
+ value = value.to_i
64
+
65
+ if @loopable
66
+ value = count == 0 ? 0 : value % count # Avoids value = value % 0 (divide by zero error)
67
+ else
68
+ value = 0 if value <= 0
69
+ value = count - 1 if value >= count - 1
70
+ end
71
+
72
+ @selected_index = value
73
+
74
+ application.dispatch_event(:selected, target: self)
75
+
76
+ @selected_index
77
+ end
78
+
79
+ # Get the child at the selected index.
80
+ #
81
+ # @return [Component]
82
+ def selected_child
83
+ @children[@selected_index]
84
+ end
85
+
86
+ # Add a child to this group.
87
+ #
88
+ # @param [Component] component
89
+ # @param [Object] object An arbitrary object to associate with the added child in this listbox.
90
+ # @return [Component]
91
+ def add_child(component, object=nil)
92
+ child = super(component)
93
+
94
+ @objects << object
95
+
96
+ child
97
+ end
98
+
99
+ # Remove a child from this listbox's children at the given index.
100
+ #
101
+ # @param [#to_i] index
102
+ # @return [Component]
103
+ def delete_child_at(index)
104
+ deleted_child = super
105
+
106
+ @objects.delete_at(index)
107
+ self.selected_index = @children.length - 1 if @selected_index >= @children.length
108
+
109
+ deleted_child
110
+ end
111
+
112
+ # Get the associated object with the child at the given index.
113
+ #
114
+ # @param [#to_i] index
115
+ # @return [Object]
116
+ def object_at(index)
117
+ @objects[index]
118
+ end
119
+
120
+ # Get the object associated with the child at the selected index.
121
+ #
122
+ # @return [Component]
123
+ def selected_object
124
+ @objects[@selected_index]
125
+ end
126
+
127
+ # Get whether this listbox is loopable or not.
128
+ #
129
+ # @return [Boolean]
130
+ def loopable?
131
+ @loopable
132
+ end
133
+
134
+ # Set whether this listbox is loopable or not.
135
+ #
136
+ # @param [Object] value
137
+ # @return [Boolean]
138
+ def loopable=(value)
139
+ @loopable = !!value
140
+ end
141
+
142
+ protected
143
+
144
+ def set_cursor_position
145
+ cursor.x = @children.empty? ? absolute_x : selected_child.absolute_x
146
+ cursor.y = @children.empty? ? absolute_y : selected_child.absolute_y
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+ end
@@ -0,0 +1,144 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_orientation"
3
+ require "cura/component/group"
4
+ end
5
+
6
+ module Cura
7
+ module Component
8
+
9
+ # A component with children which moves and optionally resizes them.
10
+ # TODO: Expand attribute - See: http://www.pygtk.org/pygtk2tutorial/sec-DetailsOfBoxes.html
11
+ # TODO: I think the only time it needs to pack_children is right before drawing? Would that get messy?
12
+ class Pack < Group
13
+
14
+ include Attributes::HasOrientation
15
+
16
+ def initialize(attributes={})
17
+ @fill = false
18
+ @spacing = 0
19
+
20
+ # @child_modifiers
21
+ super
22
+ end
23
+
24
+ # Set the width dimension of this pack.
25
+ def width=(value)
26
+ result = super
27
+
28
+ pack_children
29
+
30
+ result
31
+ end
32
+
33
+ # Set the height dimension of this pack.
34
+ def height=(value)
35
+ result = super
36
+
37
+ pack_children
38
+
39
+ result
40
+ end
41
+
42
+ # Add a child to this group.
43
+ #
44
+ # @param [Component] component
45
+ # @param [#to_hash, #to_h] options
46
+ # @option options [#to_i] :expand
47
+ # The new child is to be given extra space. The extra space will be divided evenly between all children that use this option.
48
+ # @option options [#to_i] :fill
49
+ # The space given to child by the expand option is actually allocated to child, rather than just padding it.
50
+ # This parameter has no effect if expand is set to false.
51
+ # @return [Component]
52
+ def add_child(component)
53
+ child = super
54
+
55
+ pack_children
56
+
57
+ child
58
+ end
59
+
60
+ # Remove a child from this object's children at the given index.
61
+ #
62
+ # @param [#to_i] index
63
+ # @return [Component]
64
+ def delete_child_at(index)
65
+ child = super
66
+
67
+ pack_children
68
+
69
+ child
70
+ end
71
+
72
+ # Get whether children will be filled.
73
+ # If this pack's orientation is set to :vertical, then the children's width will be set to this pack's width.
74
+ # If this pack's orientation is set to :horizontal, then the children's height will be set to this pack's width.
75
+ #
76
+ # @return [Boolean]
77
+ def fill?
78
+ @fill
79
+ end
80
+
81
+ # Set whether children will be filled.
82
+ # Must be truthy or falsey.
83
+ #
84
+ # If set to a truthy value, children will be resized to fit the space available to it.
85
+ # For example, if orientation is set to :horizontal, then all of the children's width attributes
86
+ # will be set to this instance's width.
87
+ #
88
+ # @param [Object] value
89
+ # @return [Boolean]
90
+ def fill=(value)
91
+ @fill = !!value
92
+ end
93
+
94
+ # Get the spacing between children.
95
+ #
96
+ # @return [Integer]
97
+ attr_reader :spacing
98
+
99
+ # Set the spacing between children.
100
+ #
101
+ # @param [#to_i] value
102
+ # @return [Integer]
103
+ def spacing=(value)
104
+ value = value.to_i
105
+ value = 0 if value < 0
106
+
107
+ @spacing = value
108
+ end
109
+
110
+ # Draw this pack.
111
+ #
112
+ # @return [Pack]
113
+ def draw
114
+ pack_children
115
+
116
+ super
117
+ end
118
+
119
+ protected
120
+
121
+ # Position and resize this pack's children based on it's attributes.
122
+ def pack_children
123
+ child_x = 0
124
+ child_y = 0
125
+
126
+ children.each do |child|
127
+ if horizontal?
128
+ child.x = child_x
129
+ child_x += child.width + child.offsets.width + spacing
130
+
131
+ child.height = height if fill?
132
+ elsif vertical?
133
+ child.y = child_y if vertical?
134
+ child_y += child.height + child.offsets.height + spacing
135
+
136
+ child.width = width if fill?
137
+ end
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,184 @@
1
+ if Kernel.respond_to?(:require)
2
+ require "cura/attributes/has_orientation"
3
+ require "cura/component/group"
4
+ require "cura/component/button"
5
+ end
6
+
7
+ module Cura
8
+ module Component
9
+
10
+ # A component for scrolling.
11
+ # TODO: Option to have buttons or not
12
+ class Scrollbar < Group
13
+
14
+ include Attributes::HasOrientation
15
+
16
+ def initialize(attributes={})
17
+ @value = 0
18
+ @min = 0
19
+ @max = 100
20
+ @orientation = :vertical
21
+ @buttons = {}
22
+
23
+ @buttons[:decrement] = Button.new(width: 1, height: 1) { parent.decrement }
24
+ @buttons[:increment] = Button.new(width: 1, height: 1) { parent.increment }
25
+ @handle = Component.new(width: 1, height: 1)
26
+
27
+ super
28
+
29
+ setup_value
30
+ setup_buttons
31
+ setup_handle
32
+
33
+ set_button_labels_based_on_orientation
34
+ set_button_coordinates_based_on_orientation
35
+ set_percentage
36
+ set_handle_position
37
+ end
38
+
39
+ # Get the buttons for this scrollbar.
40
+ attr_reader :buttons
41
+
42
+ # Get the value of this scrollbar.
43
+ attr_reader :value
44
+
45
+ # Set the value of this scrollbar.
46
+ def value=(value)
47
+ raise ArgumentError, "value must respond to :to_i" unless value.respond_to?(:to_i)
48
+
49
+ value = max if value > max
50
+ value = min if value < min
51
+
52
+ @value = value.to_i
53
+
54
+ set_percentage
55
+ set_handle_position
56
+ end
57
+
58
+ # Get the percentage of this scrollbar.
59
+ attr_reader :percent
60
+
61
+ # Set the width of this scrollbar.
62
+ def width=(value)
63
+ super
64
+
65
+ # @width = 2 if @width == 0 # TODO: Depends on if buttons are shown or not AND orientation
66
+
67
+ set_button_coordinates_based_on_orientation
68
+ end
69
+
70
+ # Set the height of this scrollbar.
71
+ def height=(value)
72
+ super
73
+
74
+ # @height = 2 if @height == 0 # TODO: Depends on if buttons are shown or not AND orientation
75
+
76
+ set_button_coordinates_based_on_orientation
77
+ end
78
+
79
+ # Get the minimum value of this scrollbar.
80
+ attr_reader :min
81
+
82
+ # Set the minimum value of this scrollbar.
83
+ def min=(value)
84
+ raise ArgumentError, "min must respond to :to_i" unless value.respond_to?(:to_i)
85
+
86
+ @min = value.to_i
87
+ end
88
+
89
+ # Get the maximum value of this scrollbar.
90
+ attr_reader :max
91
+
92
+ # Set the maximum value of this scrollbar.
93
+ def max=(value)
94
+ raise ArgumentError, "max must respond to :to_i" unless value.respond_to?(:to_i)
95
+
96
+ @max = value.to_i
97
+ end
98
+
99
+ # Set the orientation of this scrollbar.
100
+ def orientation=(value)
101
+ super
102
+
103
+ set_button_labels_based_on_orientation
104
+ end
105
+
106
+ # Increment the value of this scrollbar by the given number.
107
+ def increment(value=1)
108
+ raise ArgumentError, "value must respond to :to_i" unless value.respond_to?(:to_i)
109
+
110
+ self.value += value.to_i
111
+ end
112
+
113
+ # Decrement the value of this scrollbar by the given number.
114
+ def decrement(value=1)
115
+ raise ArgumentError, "value must respond to :to_i" unless value.respond_to?(:to_i)
116
+
117
+ self.value -= value.to_i
118
+ end
119
+
120
+ protected
121
+
122
+ def setup_value
123
+ @value = min if value < min
124
+ @value = max if value > max
125
+ end
126
+
127
+ def setup_buttons
128
+ @buttons.each do |_, button|
129
+ button.foreground = foreground
130
+ button.background = background
131
+
132
+ add(button)
133
+ end
134
+ end
135
+
136
+ def setup_handle
137
+ @handle.foreground = background
138
+ @handle.background = foreground
139
+
140
+ add(@handle)
141
+ end
142
+
143
+ def set_button_labels_based_on_orientation
144
+ if vertical?
145
+ @buttons[:decrement].text = "˄"
146
+ @buttons[:increment].text = "˅"
147
+ elsif horizontal?
148
+ @buttons[:decrement].text = "˂"
149
+ @buttons[:increment].text = "˃"
150
+ end
151
+ end
152
+
153
+ def set_button_coordinates_based_on_orientation
154
+ if vertical?
155
+ @buttons[:increment].x = 0
156
+ @buttons[:increment].y = height - 1
157
+ elsif horizontal?
158
+ @buttons[:increment].x = width - 1
159
+ @buttons[:increment].y = 0
160
+ end
161
+ end
162
+
163
+ def set_percentage
164
+ @percent = ((value.to_f - min.to_f) / (max.to_f - min.to_f) * 100.0).to_i
165
+ end
166
+
167
+ def set_handle_position
168
+ # TODO: Only +/- padding when buttons are shown
169
+ dimension = (vertical? ? height : width) - 3
170
+ position = (dimension.to_f * percent.to_f / 100.0).to_i + 1
171
+
172
+ if vertical?
173
+ @handle.x = 0
174
+ @handle.y = position
175
+ elsif horizontal?
176
+ @handle.x = position
177
+ @handle.y = 0
178
+ end
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+ end