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.
- checksums.yaml +7 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +122 -0
- data/LICENSE +20 -0
- data/README.md +159 -0
- data/Rakefile +42 -0
- data/cura.gemspec +23 -0
- data/examples/box_model/bin/box_model +11 -0
- data/examples/box_model/debug.log +0 -0
- data/examples/box_model/lib/box_model.rb +21 -0
- data/examples/box_model/lib/box_model/application.rb +24 -0
- data/examples/hello_world/bin/hello_world +10 -0
- data/examples/hello_world/lib/hello_world.rb +201 -0
- data/examples/mruby-examples/README.md +10 -0
- data/examples/mruby-examples/include/cura_examples.h +6 -0
- data/examples/mruby-examples/mrbgem.rake +14 -0
- data/examples/mruby-examples/src/gem_init.c +34 -0
- data/examples/mruby-examples/tools/hello_world/hello_world.c +6 -0
- data/examples/todo_list/app.log +9 -0
- data/examples/todo_list/bin/todo_list +26 -0
- data/examples/todo_list/data.db +0 -0
- data/examples/todo_list/debug.log +0 -0
- data/examples/todo_list/lib/todo_list.rb +28 -0
- data/examples/todo_list/lib/todo_list/application.rb +54 -0
- data/examples/todo_list/lib/todo_list/component/header.rb +27 -0
- data/examples/todo_list/lib/todo_list/component/list.rb +50 -0
- data/examples/todo_list/lib/todo_list/component/list_item.rb +28 -0
- data/examples/todo_list/lib/todo_list/component/list_items.rb +97 -0
- data/examples/todo_list/lib/todo_list/component/lists.rb +89 -0
- data/examples/todo_list/lib/todo_list/database.rb +50 -0
- data/examples/todo_list/lib/todo_list/model/list.rb +9 -0
- data/examples/todo_list/lib/todo_list/model/list_item.rb +9 -0
- data/examples/todo_list/profile.html +11354 -0
- data/lib/cura.rb +13 -0
- data/lib/cura/adapter.rb +67 -0
- data/lib/cura/application.rb +245 -0
- data/lib/cura/attributes/has_ancestry.rb +40 -0
- data/lib/cura/attributes/has_application.rb +31 -0
- data/lib/cura/attributes/has_attributes.rb +89 -0
- data/lib/cura/attributes/has_children.rb +113 -0
- data/lib/cura/attributes/has_colors.rb +66 -0
- data/lib/cura/attributes/has_coordinates.rb +49 -0
- data/lib/cura/attributes/has_dimensions.rb +63 -0
- data/lib/cura/attributes/has_events.rb +89 -0
- data/lib/cura/attributes/has_focusability.rb +37 -0
- data/lib/cura/attributes/has_initialize.rb +15 -0
- data/lib/cura/attributes/has_offsets.rb +82 -0
- data/lib/cura/attributes/has_orientation.rb +53 -0
- data/lib/cura/attributes/has_relative_coordinates.rb +39 -0
- data/lib/cura/attributes/has_root.rb +104 -0
- data/lib/cura/attributes/has_side_attributes.rb +95 -0
- data/lib/cura/attributes/has_windows.rb +70 -0
- data/lib/cura/borders.rb +16 -0
- data/lib/cura/color.rb +330 -0
- data/lib/cura/component/base.rb +180 -0
- data/lib/cura/component/button.rb +57 -0
- data/lib/cura/component/group.rb +77 -0
- data/lib/cura/component/label.rb +224 -0
- data/lib/cura/component/listbox.rb +152 -0
- data/lib/cura/component/pack.rb +144 -0
- data/lib/cura/component/scrollbar.rb +184 -0
- data/lib/cura/component/textbox.rb +118 -0
- data/lib/cura/cursor.rb +77 -0
- data/lib/cura/error/base.rb +10 -0
- data/lib/cura/error/invalid_adapter.rb +18 -0
- data/lib/cura/error/invalid_application.rb +18 -0
- data/lib/cura/error/invalid_color.rb +18 -0
- data/lib/cura/error/invalid_component.rb +18 -0
- data/lib/cura/error/invalid_middleware.rb +18 -0
- data/lib/cura/event.rb +38 -0
- data/lib/cura/event/base.rb +108 -0
- data/lib/cura/event/click.rb +14 -0
- data/lib/cura/event/dispatcher.rb +122 -0
- data/lib/cura/event/focus.rb +14 -0
- data/lib/cura/event/handler.rb +74 -0
- data/lib/cura/event/key_down.rb +68 -0
- data/lib/cura/event/middleware/aimer/base.rb +38 -0
- data/lib/cura/event/middleware/aimer/dispatcher_target.rb +24 -0
- data/lib/cura/event/middleware/aimer/mouse_focus.rb +48 -0
- data/lib/cura/event/middleware/aimer/target_option.rb +38 -0
- data/lib/cura/event/middleware/base.rb +21 -0
- data/lib/cura/event/middleware/dispatch.rb +20 -0
- data/lib/cura/event/middleware/translator/base.rb +37 -0
- data/lib/cura/event/middleware/translator/mouse_click.rb +44 -0
- data/lib/cura/event/mouse.rb +34 -0
- data/lib/cura/event/mouse_button.rb +103 -0
- data/lib/cura/event/mouse_wheel_down.rb +14 -0
- data/lib/cura/event/mouse_wheel_up.rb +14 -0
- data/lib/cura/event/resize.rb +17 -0
- data/lib/cura/event/selected.rb +14 -0
- data/lib/cura/event/unfocus.rb +14 -0
- data/lib/cura/focus_controller.rb +89 -0
- data/lib/cura/key.rb +313 -0
- data/lib/cura/margins.rb +16 -0
- data/lib/cura/offsets.rb +91 -0
- data/lib/cura/padding.rb +16 -0
- data/lib/cura/pencil.rb +29 -0
- data/lib/cura/version.rb +6 -0
- data/lib/cura/window.rb +85 -0
- data/spec/cura/attributes/has_ancestry_spec.rb +108 -0
- data/spec/cura/attributes/has_application_spec.rb +59 -0
- data/spec/cura/attributes/has_attributes_spec.rb +75 -0
- data/spec/cura/attributes/has_children_spec.rb +169 -0
- data/spec/cura/attributes/has_colors_spec.rb +20 -0
- data/spec/cura/attributes/has_coordinates_spec.rb +19 -0
- data/spec/cura/attributes/has_dimensions_spec.rb +19 -0
- data/spec/cura/attributes/has_events_spec.rb +18 -0
- data/spec/cura/attributes/has_focusability_spec.rb +58 -0
- data/spec/cura/attributes/has_offsets_spec.rb +18 -0
- data/spec/cura/attributes/has_orientation_spec.rb +102 -0
- data/spec/cura/attributes/has_relative_coordinates_spec.rb +18 -0
- data/spec/cura/attributes/has_side_attributes_spec.rb +19 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/shared_examples_for_attributes.rb +122 -0
- 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
|
data/lib/cura/cursor.rb
ADDED
@@ -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,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
|
data/lib/cura/event.rb
ADDED
@@ -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
|