fusuma 0.11.1 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +8 -0
- data/.gitignore +6 -0
- data/.reek.yml +93 -45
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +16 -75
- data/Gemfile +2 -0
- data/README.md +12 -5
- data/Rakefile +2 -1
- data/bin/console +1 -1
- data/exe/fusuma +1 -0
- data/fusuma.gemspec +9 -2
- data/lib/fusuma.rb +88 -31
- data/lib/fusuma/config.rb +65 -66
- data/lib/fusuma/config/index.rb +49 -0
- data/lib/fusuma/device.rb +58 -37
- data/lib/fusuma/multi_logger.rb +3 -0
- data/lib/fusuma/plugin/base.rb +56 -0
- data/lib/fusuma/plugin/buffers/buffer.rb +41 -0
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +70 -0
- data/lib/fusuma/plugin/detectors/detector.rb +41 -0
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +141 -0
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +135 -0
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +145 -0
- data/lib/fusuma/plugin/events/event.rb +38 -0
- data/lib/fusuma/plugin/events/records/gesture_record.rb +31 -0
- data/lib/fusuma/plugin/events/records/index_record.rb +53 -0
- data/lib/fusuma/plugin/events/records/record.rb +20 -0
- data/lib/fusuma/plugin/events/records/text_record.rb +28 -0
- data/lib/fusuma/plugin/executors/command_executor.rb +39 -0
- data/lib/fusuma/plugin/executors/executor.rb +27 -0
- data/lib/fusuma/plugin/filters/filter.rb +40 -0
- data/lib/fusuma/plugin/filters/libinput_device_filter.rb +42 -0
- data/lib/fusuma/plugin/inputs/input.rb +28 -0
- data/lib/fusuma/plugin/inputs/libinput_command_input.rb +133 -0
- data/lib/fusuma/plugin/manager.rb +118 -0
- data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +54 -0
- data/lib/fusuma/plugin/parsers/parser.rb +46 -0
- data/lib/fusuma/version.rb +3 -1
- metadata +74 -14
- data/lib/fusuma/command_executor.rb +0 -43
- data/lib/fusuma/event_stack.rb +0 -87
- data/lib/fusuma/gesture_event.rb +0 -50
- data/lib/fusuma/libinput_commands.rb +0 -98
- data/lib/fusuma/pinch.rb +0 -58
- data/lib/fusuma/swipe.rb +0 -59
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base.rb'
|
4
|
+
|
5
|
+
module Fusuma
|
6
|
+
module Plugin
|
7
|
+
module Buffers
|
8
|
+
# buffer events and output
|
9
|
+
class Buffer < Base
|
10
|
+
def initialize(*args)
|
11
|
+
@events = Array.new(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :events
|
15
|
+
|
16
|
+
# @return [String]
|
17
|
+
def type
|
18
|
+
self.class.name.underscore.split('/').last.gsub('_buffer', '')
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param event [Event]
|
22
|
+
def buffer(event)
|
23
|
+
return if event&.tag != source
|
24
|
+
|
25
|
+
@events.push(event)
|
26
|
+
end
|
27
|
+
|
28
|
+
# clear buffer
|
29
|
+
def clear
|
30
|
+
@events.clear
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set source for tag from config.yml.
|
34
|
+
# DEFAULT_SOURCE is defined in each plugins.
|
35
|
+
def source
|
36
|
+
@source ||= config_params(:source) || self.class.const_get('DEFAULT_SOURCE')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './buffer.rb'
|
4
|
+
|
5
|
+
module Fusuma
|
6
|
+
module Plugin
|
7
|
+
module Buffers
|
8
|
+
# manage events and generate command
|
9
|
+
class GestureBuffer < Buffer
|
10
|
+
DEFAULT_SOURCE = 'libinput_gesture_parser'
|
11
|
+
|
12
|
+
# @param event [Event]
|
13
|
+
def buffer(event)
|
14
|
+
# TODO: buffering events into buffer plugins
|
15
|
+
# - gesture event buffer
|
16
|
+
# - window event buffer
|
17
|
+
# - other event buffer
|
18
|
+
return if event&.tag != source
|
19
|
+
return if event.record.type != :gesture
|
20
|
+
|
21
|
+
@events.push(event)
|
22
|
+
clear unless updating?
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param attr [Symbol]
|
26
|
+
# @return [Float]
|
27
|
+
def sum_attrs(attr)
|
28
|
+
@events.map { |gesture_event| gesture_event.record.direction[attr].to_f }
|
29
|
+
.inject(:+)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param attr [Symbol]
|
33
|
+
# @return [Float]
|
34
|
+
def avg_attrs(attr)
|
35
|
+
sum_attrs(attr).to_f / @events.length
|
36
|
+
end
|
37
|
+
|
38
|
+
# return [Integer]
|
39
|
+
def finger
|
40
|
+
@events.last.record.finger.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
# @example
|
44
|
+
# event_buffer.gesture
|
45
|
+
# => 'swipe'
|
46
|
+
# @return [String]
|
47
|
+
def gesture
|
48
|
+
@events.last.record.gesture
|
49
|
+
end
|
50
|
+
|
51
|
+
def empty?
|
52
|
+
@events.empty?
|
53
|
+
end
|
54
|
+
|
55
|
+
def select_by_events
|
56
|
+
return enum_for(:select) unless block_given?
|
57
|
+
|
58
|
+
events = @events.select { |event| yield event }
|
59
|
+
self.class.new events
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def updating?
|
65
|
+
return true unless @events.last.record.status =~ /begin|end/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../base.rb'
|
4
|
+
require_relative '../events/event.rb'
|
5
|
+
|
6
|
+
module Fusuma
|
7
|
+
module Plugin
|
8
|
+
module Detectors
|
9
|
+
# Inherite this base
|
10
|
+
class Detector < Base
|
11
|
+
# @param _buffers [Array<Buffer>]
|
12
|
+
# @return [Event] if event is detected
|
13
|
+
# @return [NilClass] if event is NOT detected
|
14
|
+
def detect(_buffers)
|
15
|
+
raise NotImplementedError, "override #{self.class.name}##{__method__}"
|
16
|
+
|
17
|
+
# create_event(record:)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param record [Events::Records::Record]
|
21
|
+
# @return [Events::Event]
|
22
|
+
def create_event(record:)
|
23
|
+
@last_time = Time.now
|
24
|
+
Events::Event.new(time: Time.now, tag: tag, record: record)
|
25
|
+
end
|
26
|
+
|
27
|
+
def last_time
|
28
|
+
@last_time ||= Time.now
|
29
|
+
end
|
30
|
+
|
31
|
+
def tag
|
32
|
+
self.class.name.split('Detectors::').last.underscore
|
33
|
+
end
|
34
|
+
|
35
|
+
def type
|
36
|
+
self.class.name.underscore.split('/').last.gsub('_detector', '')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './detector.rb'
|
4
|
+
|
5
|
+
module Fusuma
|
6
|
+
module Plugin
|
7
|
+
module Detectors
|
8
|
+
class PinchDetector < Detector
|
9
|
+
BUFFER_TYPE = 'gesture'
|
10
|
+
GESTURE_RECORD_TYPE = 'pinch'
|
11
|
+
|
12
|
+
FINGERS = [2, 3, 4].freeze
|
13
|
+
BASE_THERESHOLD = 0.1
|
14
|
+
BASE_INTERVAL = 0.1
|
15
|
+
|
16
|
+
# @param buffers [Array<Buffer>]
|
17
|
+
# @return [Event] if event is detected
|
18
|
+
# @return [NilClass] if event is NOT detected
|
19
|
+
def detect(buffers)
|
20
|
+
buffer = buffers.find { |b| b.type == BUFFER_TYPE }
|
21
|
+
.select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
|
22
|
+
|
23
|
+
return if buffer.empty?
|
24
|
+
|
25
|
+
finger = buffer.finger
|
26
|
+
|
27
|
+
avg_zoom = buffer.avg_attrs(:zoom)
|
28
|
+
first_zoom = buffer.events.first.record.direction.zoom
|
29
|
+
diameter = avg_zoom / first_zoom
|
30
|
+
|
31
|
+
direction = Direction.new(diameter: diameter).to_s
|
32
|
+
quantity = Quantity.new(diameter: diameter).to_f
|
33
|
+
|
34
|
+
index = create_index(gesture: type,
|
35
|
+
finger: finger,
|
36
|
+
direction: direction)
|
37
|
+
|
38
|
+
return unless enough?(index: index, quantity: quantity)
|
39
|
+
|
40
|
+
create_event(record: Events::Records::IndexRecord.new(index: index))
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [String] gesture
|
44
|
+
# @param [Integer] finger
|
45
|
+
# @param [String] direction
|
46
|
+
# @return [Config::Index]
|
47
|
+
def create_index(gesture:, finger:, direction:)
|
48
|
+
Config::Index.new(
|
49
|
+
[
|
50
|
+
Config::Index::Key.new(gesture),
|
51
|
+
Config::Index::Key.new(finger.to_i, skippable: true),
|
52
|
+
Config::Index::Key.new(direction)
|
53
|
+
]
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def enough?(index:, quantity:)
|
60
|
+
enough_interval?(index: index) && enough_diameter?(index: index, quantity: quantity)
|
61
|
+
end
|
62
|
+
|
63
|
+
def enough_diameter?(index:, quantity:)
|
64
|
+
MultiLogger.info(type: type, quantity: quantity,
|
65
|
+
quantity_threshold: threshold(index: index))
|
66
|
+
quantity >= threshold(index: index)
|
67
|
+
end
|
68
|
+
|
69
|
+
def enough_interval?(index:)
|
70
|
+
return true if first_time?
|
71
|
+
return true if (Time.now - @last_time) > interval_time(index: index)
|
72
|
+
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
def first_time?
|
77
|
+
!@last_time
|
78
|
+
end
|
79
|
+
|
80
|
+
def threshold(index:)
|
81
|
+
@threshold ||= {}
|
82
|
+
@threshold[index.cache_key] ||= begin
|
83
|
+
keys_specific = Config::Index.new [*index.keys, 'threshold']
|
84
|
+
keys_global = Config::Index.new ['threshold', type]
|
85
|
+
config_value = Config.search(keys_specific) ||
|
86
|
+
Config.search(keys_global) || 1
|
87
|
+
BASE_THERESHOLD * config_value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def interval_time(index:)
|
92
|
+
@interval_time ||= {}
|
93
|
+
@interval_time[index.cache_key] ||= begin
|
94
|
+
keys_specific = Config::Index.new [*index.keys, 'interval']
|
95
|
+
keys_global = Config::Index.new ['interval', type]
|
96
|
+
config_value = Config.search(keys_specific) ||
|
97
|
+
Config.search(keys_global) || 1
|
98
|
+
BASE_INTERVAL * config_value
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# direction of gesture
|
103
|
+
class Direction
|
104
|
+
IN = 'in'
|
105
|
+
OUT = 'out'
|
106
|
+
|
107
|
+
def initialize(diameter:)
|
108
|
+
@diameter = diameter
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_s
|
112
|
+
calc
|
113
|
+
end
|
114
|
+
|
115
|
+
def calc
|
116
|
+
if @diameter > 1
|
117
|
+
IN
|
118
|
+
else
|
119
|
+
OUT
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# quantity of gesture
|
125
|
+
class Quantity
|
126
|
+
def initialize(diameter:)
|
127
|
+
@diameter = diameter
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_f
|
131
|
+
calc.to_f
|
132
|
+
end
|
133
|
+
|
134
|
+
def calc
|
135
|
+
(1.0 - @diameter).abs
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './detector.rb'
|
4
|
+
|
5
|
+
module Fusuma
|
6
|
+
module Plugin
|
7
|
+
module Detectors
|
8
|
+
class RotateDetector < Detector
|
9
|
+
BUFFER_TYPE = 'gesture'
|
10
|
+
GESTURE_RECORD_TYPE = 'pinch'
|
11
|
+
|
12
|
+
FINGERS = [2, 3, 4].freeze
|
13
|
+
BASE_THERESHOLD = 0.5
|
14
|
+
BASE_INTERVAL = 0.1
|
15
|
+
|
16
|
+
# @param buffers [Array<Buffer>]
|
17
|
+
# @return [Event] if event is detected
|
18
|
+
# @return [NilClass] if event is NOT detected
|
19
|
+
def detect(buffers)
|
20
|
+
buffer = buffers.find { |b| b.type == BUFFER_TYPE }
|
21
|
+
.select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
|
22
|
+
|
23
|
+
return if buffer.empty?
|
24
|
+
|
25
|
+
angle = buffer.avg_attrs(:rotate)
|
26
|
+
|
27
|
+
finger = buffer.finger
|
28
|
+
direction = Direction.new(angle: angle).to_s
|
29
|
+
quantity = Quantity.new(angle: angle).to_f
|
30
|
+
|
31
|
+
index = create_index(gesture: type,
|
32
|
+
finger: finger,
|
33
|
+
direction: direction)
|
34
|
+
|
35
|
+
return unless enough?(index: index, quantity: quantity)
|
36
|
+
|
37
|
+
create_event(record: Events::Records::IndexRecord.new(index: index))
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [String] gesture
|
41
|
+
# @param [Integer] finger
|
42
|
+
# @param [String] direction
|
43
|
+
# @return [Config::Index]
|
44
|
+
def create_index(gesture:, finger:, direction:)
|
45
|
+
Config::Index.new(
|
46
|
+
[
|
47
|
+
Config::Index::Key.new(gesture),
|
48
|
+
Config::Index::Key.new(finger.to_i, skippable: true),
|
49
|
+
Config::Index::Key.new(direction)
|
50
|
+
]
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def enough?(index:, quantity:)
|
57
|
+
enough_interval?(index: index) && enough_angle?(index: index, quantity: quantity)
|
58
|
+
end
|
59
|
+
|
60
|
+
def enough_angle?(index:, quantity:)
|
61
|
+
MultiLogger.info(type: type, quantity: quantity,
|
62
|
+
quantity_threshold: threshold(index: index))
|
63
|
+
|
64
|
+
quantity > threshold(index: index)
|
65
|
+
end
|
66
|
+
|
67
|
+
def enough_interval?(index:)
|
68
|
+
return true if first_time?
|
69
|
+
return true if (Time.now - @last_time) > interval_time(index: index)
|
70
|
+
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
def first_time?
|
75
|
+
!@last_time
|
76
|
+
end
|
77
|
+
|
78
|
+
def threshold(index:)
|
79
|
+
@threshold ||= {}
|
80
|
+
@threshold[index.cache_key] ||= begin
|
81
|
+
keys_specific = Config::Index.new [*index.keys, 'threshold']
|
82
|
+
keys_global = Config::Index.new ['threshold', type]
|
83
|
+
config_value = Config.search(keys_specific) ||
|
84
|
+
Config.search(keys_global) || 1
|
85
|
+
BASE_THERESHOLD * config_value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def interval_time(index:)
|
90
|
+
@interval_time ||= {}
|
91
|
+
@interval_time[index.cache_key] ||= begin
|
92
|
+
keys_specific = Config::Index.new [*index.keys, 'interval']
|
93
|
+
keys_global = Config::Index.new ['interval', type]
|
94
|
+
config_value = Config.search(keys_specific) ||
|
95
|
+
Config.search(keys_global) || 1
|
96
|
+
BASE_INTERVAL * config_value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# direction of gesture
|
101
|
+
class Direction
|
102
|
+
CLOCKWISE = 'clockwise'
|
103
|
+
COUNTERCLOCKWISE = 'counterclockwise'
|
104
|
+
|
105
|
+
def initialize(angle:)
|
106
|
+
@angle = angle
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
calc
|
111
|
+
end
|
112
|
+
|
113
|
+
def calc
|
114
|
+
if @angle > 0
|
115
|
+
CLOCKWISE
|
116
|
+
else
|
117
|
+
COUNTERCLOCKWISE
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# quantity of gesture
|
123
|
+
class Quantity
|
124
|
+
def initialize(angle:)
|
125
|
+
@angle = angle.abs
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_f
|
129
|
+
@angle.to_f
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './detector.rb'
|
4
|
+
|
5
|
+
module Fusuma
|
6
|
+
module Plugin
|
7
|
+
module Detectors
|
8
|
+
class SwipeDetector < Detector
|
9
|
+
BUFFER_TYPE = 'gesture'
|
10
|
+
GESTURE_RECORD_TYPE = 'swipe'
|
11
|
+
|
12
|
+
FINGERS = [3, 4].freeze
|
13
|
+
BASE_THERESHOLD = 10
|
14
|
+
BASE_INTERVAL = 0.5
|
15
|
+
|
16
|
+
# @param buffers [Array<Buffers::Buffer>]
|
17
|
+
# @return [Event] if event is detected
|
18
|
+
# @return [NilClass] if event is NOT detected
|
19
|
+
def detect(buffers)
|
20
|
+
buffer = buffers.find { |b| b.type == BUFFER_TYPE }
|
21
|
+
.select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
|
22
|
+
|
23
|
+
return if buffer.empty?
|
24
|
+
|
25
|
+
move_x = buffer.avg_attrs(:move_x)
|
26
|
+
move_y = buffer.avg_attrs(:move_y)
|
27
|
+
|
28
|
+
finger = buffer.finger
|
29
|
+
direction = Direction.new(move_x: move_x.to_f, move_y: move_y.to_f).to_s
|
30
|
+
quantity = Quantity.new(move_x: move_x.to_f, move_y: move_y.to_f).to_f
|
31
|
+
|
32
|
+
index = create_index(gesture: type,
|
33
|
+
finger: finger,
|
34
|
+
direction: direction)
|
35
|
+
|
36
|
+
return unless enough?(index: index, quantity: quantity)
|
37
|
+
|
38
|
+
create_event(record: Events::Records::IndexRecord.new(index: index))
|
39
|
+
end
|
40
|
+
|
41
|
+
# @param [String] gesture
|
42
|
+
# @param [Integer] finger
|
43
|
+
# @param [String] direction
|
44
|
+
# @return [Config::Index]
|
45
|
+
def create_index(gesture:, finger:, direction:)
|
46
|
+
Config::Index.new(
|
47
|
+
[
|
48
|
+
Config::Index::Key.new(gesture),
|
49
|
+
Config::Index::Key.new(finger.to_i, skippable: true),
|
50
|
+
Config::Index::Key.new(direction)
|
51
|
+
]
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def enough?(index:, quantity:)
|
58
|
+
enough_interval?(index: index) && enough_distance?(index: index, quantity: quantity)
|
59
|
+
end
|
60
|
+
|
61
|
+
def enough_distance?(index:, quantity:)
|
62
|
+
MultiLogger.info(type: type, quantity: quantity,
|
63
|
+
quantity_threshold: threshold(index: index))
|
64
|
+
quantity > threshold(index: index)
|
65
|
+
end
|
66
|
+
|
67
|
+
def enough_interval?(index:)
|
68
|
+
return true if first_time?
|
69
|
+
return true if (Time.now - @last_time) > interval_time(index: index)
|
70
|
+
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
def first_time?
|
75
|
+
!@last_time
|
76
|
+
end
|
77
|
+
|
78
|
+
def threshold(index:)
|
79
|
+
@threshold ||= {}
|
80
|
+
@threshold[index.cache_key] ||= begin
|
81
|
+
keys_specific = Config::Index.new [*index.keys, 'threshold']
|
82
|
+
keys_global = Config::Index.new ['threshold', type]
|
83
|
+
config_value = Config.search(keys_specific) ||
|
84
|
+
Config.search(keys_global) || 1
|
85
|
+
BASE_THERESHOLD * config_value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def interval_time(index:)
|
90
|
+
@interval_time ||= {}
|
91
|
+
@interval_time[index.cache_key] ||= begin
|
92
|
+
keys_specific = Config::Index.new [*index.keys, 'interval']
|
93
|
+
keys_global = Config::Index.new ['interval', type]
|
94
|
+
config_value = Config.search(keys_specific) ||
|
95
|
+
Config.search(keys_global) || 1
|
96
|
+
BASE_INTERVAL * config_value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# direction of gesture
|
101
|
+
class Direction
|
102
|
+
RIGHT = 'right'
|
103
|
+
LEFT = 'left'
|
104
|
+
DOWN = 'down'
|
105
|
+
UP = 'up'
|
106
|
+
|
107
|
+
def initialize(move_x:, move_y:)
|
108
|
+
@move_x = move_x
|
109
|
+
@move_y = move_y
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_s
|
113
|
+
calc
|
114
|
+
end
|
115
|
+
|
116
|
+
def calc
|
117
|
+
if @move_x.abs > @move_y.abs
|
118
|
+
@move_x > 0 ? RIGHT : LEFT
|
119
|
+
elsif @move_y > 0
|
120
|
+
DOWN
|
121
|
+
else
|
122
|
+
UP
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# quantity of gesture
|
128
|
+
class Quantity
|
129
|
+
def initialize(move_x:, move_y:)
|
130
|
+
@x = move_x.abs
|
131
|
+
@y = move_y.abs
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_f
|
135
|
+
calc.to_f
|
136
|
+
end
|
137
|
+
|
138
|
+
def calc
|
139
|
+
@x > @y ? @x.abs : @y.abs
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|