hokusai-zero 0.2.6.pre.pinephone → 0.2.6.pre.pinephone3

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.
@@ -0,0 +1,139 @@
1
+
2
+ module Hokusai::Blocks
3
+ class Slider < Hokusai::Block
4
+ template <<~EOF
5
+ [template]
6
+ empty {
7
+ @click="start_slider"
8
+ @mousemove="move_slider"
9
+ @mouseup="stop_slider"
10
+ }
11
+ EOF
12
+
13
+ uses(empty: Hokusai::Blocks::Empty)
14
+
15
+ computed :fill, default: [61,171,211], convert: Hokusai::Color
16
+ computed :initial, default: 0.0, convert: proc(&:to_f)
17
+ computed :size, default: 50.0, convert: proc(&:to_f)
18
+ computed :step, default: 20.0, convert: proc(&:to_f)
19
+ computed :min, default: 0.0, convert: proc(&:to_f)
20
+ computed :max, default: 100.0, convert: proc(&:to_f)
21
+
22
+ attr_reader :slider_width, :slider_start, :steps_x, :steps_val
23
+ attr_accessor :sliding, :slider_x, :last_index
24
+
25
+ def initialize(**args)
26
+ @sliding = false
27
+ @slider_width = 0.0
28
+ @slider_start = 0.0
29
+ @slider_x = 0.0
30
+ @last_index = 0
31
+ @configured = false
32
+
33
+ super
34
+
35
+ @last_max = nil
36
+ end
37
+
38
+ def start_slider(event)
39
+ self.sliding = true
40
+ end
41
+
42
+ def on_resize(canvas)
43
+ # create our buckets for steps
44
+ @slider_start = canvas.x
45
+ @slider_width = canvas.width
46
+
47
+ @steps_val = [*(min..max).step(step).to_a, max]
48
+ steps_val.pop if steps_val[-1] == steps_val[-2]
49
+
50
+ step_x = (slider_width) / (steps_val.size - 1)
51
+ @steps_x = (slider_start..(slider_start + slider_width)).step(step_x).to_a
52
+
53
+ (steps_val.size - steps_x.size).times do |i|
54
+ steps_x << steps_x.last + step_x * i
55
+ end
56
+
57
+ steps_x[-1] = slider_start + slider_width if slider_start + slider_width != steps_x.last
58
+ end
59
+
60
+ def move_slider(event)
61
+ if sliding && event.left.down
62
+ pos = event.pos.x
63
+ index = steps_x.size - 1
64
+
65
+ (0...steps_x.size - 1).each do |i|
66
+ next if steps_x[i + 1] && pos - steps_x[i + 1] > step
67
+
68
+ if pos - steps_x[i] > pos - steps_x[i + 1]
69
+ index = i
70
+ break
71
+ else
72
+ index = i + 1
73
+ break
74
+ end
75
+ end
76
+
77
+ self.last_index = index
78
+
79
+ emit("updated", steps_val[index])
80
+ else
81
+ self.sliding = false
82
+ end
83
+ end
84
+
85
+ def stop_slider(event)
86
+ if event.left.up
87
+ self.sliding = false
88
+ end
89
+ end
90
+
91
+ def render(canvas)
92
+ if max != @last_max
93
+ on_resize(canvas)
94
+
95
+ @last_max = max
96
+ end
97
+
98
+ unless @setup || steps_val.nil? || initial.nil?
99
+ steps_val.each_with_index do |val, index|
100
+ if val == initial
101
+ self.last_index = index
102
+
103
+ break
104
+ end
105
+ end
106
+
107
+ @setup = true
108
+ end
109
+
110
+ slider_x = steps_x[last_index]
111
+ padding = Hokusai::Padding.new(0.0, 0.0, 0.0, 0.0)
112
+ percent = slider_x * 100.00
113
+ x = slider_x + padding.left
114
+ x = (canvas.x + canvas.width) - (size / 2) - 2 if x > (canvas.x + canvas.width) - (size / 2)
115
+ x = canvas.x if x < canvas.x
116
+ cursor = (x + size / 2)
117
+
118
+ draw do
119
+ # draw background
120
+ rect(canvas.x + padding.left, canvas.y + padding.top, canvas.width - padding.right - padding.left, size) do |command|
121
+ command.round = size / 2
122
+ command.color = Hokusai::Color.new(33, 33, 33)
123
+ command.padding = Hokusai::Padding.new(5.0, 20.0, 5.0, 20.0)
124
+ end
125
+
126
+ rect(canvas.x + padding.left + 1, canvas.y + padding.top + 1, x + (size / 2) - canvas.x - 2, size - 2) do |command|
127
+ command.round = size / 2
128
+ command.color = fill
129
+ end
130
+
131
+ circle(cursor + padding.left, canvas.y + (size / 2) + padding.top, size / 2) do |command|
132
+ command.color = Hokusai::Color.new(233, 233, 233)
133
+ end
134
+ end
135
+
136
+ yield canvas
137
+ end
138
+ end
139
+ end
@@ -11,8 +11,8 @@ module Hokusai
11
11
  @height = height.to_f
12
12
  @outline = Outline.default
13
13
  @rounding = 0.0
14
- @color = Color.new(0, 0, 0, 0)
15
- @outline_color = Color.new(0, 0, 0, 255)
14
+ @color = Color.new(255, 255, 255, 0)
15
+ @outline_color = Color.new(0, 0, 0, 0)
16
16
  @padding = Padding.new(0.0, 0.0, 0.0, 0.0)
17
17
  @gradient = nil
18
18
  end
@@ -66,4 +66,4 @@ end
66
66
 
67
67
  require_relative './events/keyboard'
68
68
  require_relative './events/mouse'
69
- require_relative './events/embedded'
69
+ require_relative './events/touch'
@@ -1,17 +1,17 @@
1
1
  module Hokusai
2
- class EmbeddedEvent < Event
2
+ class TouchEvent < Event
3
3
  extend Forwardable
4
4
 
5
- def_delegators :@embedded, :hold, :hold_duration, :drag, :drag_direction,
6
- :drag_pos, :drag_angle, :pinch,
7
- :pinch_direction, :pinch_pos, :pinch_angle
5
+ def_delegators :@touch, :tapped?, :swiped?, :longtapped?, :longtapping?, :touching?,
6
+ :duration, :direction, :distance, :angle, :position, :last_position,
7
+ :touch_len, :touch_count, :timer
8
8
 
9
9
  attr_reader :input
10
10
 
11
11
  def initialize(input, state)
12
12
  @input = input
13
13
  @state = state
14
- @embedded = input.embedded
14
+ @touch = input.touch
15
15
  end
16
16
 
17
17
  def hovered(canvas)
@@ -28,37 +28,31 @@ module Hokusai
28
28
  end
29
29
  end
30
30
 
31
- class TapHoldEvent < EmbeddedEvent
31
+ class TapHoldEvent < TouchEvent
32
32
  name "taphold"
33
33
 
34
34
  def capture(block, canvas)
35
- if hold && hovered(canvas)
36
- block.node.meta.focus
37
-
38
- if matches(block)
39
- captures << block
40
- end
41
- elsif hold
42
- block.node.meta.blur
35
+ if matches(block) && longtapped? && hovered(canvas)
36
+ captures << block
43
37
  end
44
38
  end
45
39
  end
46
40
 
47
- class PinchEvent < EmbeddedEvent
41
+ class PinchEvent < TouchEvent
48
42
  name "pinch"
49
43
 
50
44
  def capture(block, canvas)
51
- if pinch && matches(block)
45
+ if false && matches(block)
52
46
  captures << block
53
47
  end
54
48
  end
55
49
  end
56
50
 
57
- class SwipeEvent < EmbeddedEvent
51
+ class SwipeEvent < TouchEvent
58
52
  name "swipe"
59
53
 
60
54
  def capture(block, canvas)
61
- if drag && matches(block)
55
+ if swiped? && matches(block)
62
56
  captures << block
63
57
  end
64
58
  end
@@ -46,10 +46,10 @@ module Hokusai
46
46
  keypress: KeyPressEvent.new(input, state)
47
47
  }
48
48
 
49
- add_embedded_events(events, input, state) unless input.embedded.nil?
49
+ add_touch_events(events, input, state) unless input.touch.nil?
50
50
  end
51
51
 
52
- def add_embedded_events(events, input, state)
52
+ def add_touch_events(events, input, state)
53
53
  events.merge!({
54
54
  taphold: TapHoldEvent.new(input, state),
55
55
  pinch: PinchEvent.new(input, state),
@@ -181,7 +181,7 @@ module Hokusai
181
181
  events[:mousedown].bubble
182
182
  events[:mouseup].bubble
183
183
 
184
- unless input.embedded.nil?
184
+ unless input.touch.nil?
185
185
  events[:taphold].bubble
186
186
  events[:pinch].bubble
187
187
  events[:swipe].bubble
@@ -277,12 +277,12 @@ module Hokusai
277
277
  end
278
278
  events[:mousemove].capture(block, canvas)
279
279
 
280
- if block_is_hovered || block.node.meta.focused
280
+ if block_is_hovered || block.node.meta.focused || input.keyboard_override
281
281
  events[:keyup].capture(block, canvas)
282
282
  events[:keypress].capture(block, canvas)
283
283
  end
284
284
 
285
- unless input.embedded.nil?
285
+ unless input.touch.nil?
286
286
  events[:taphold].capture(block, canvas)
287
287
  events[:pinch].capture(block, canvas)
288
288
  events[:swipe].capture(block, canvas)
@@ -96,6 +96,14 @@ module Hokusai
96
96
  alias_method :r, :right
97
97
  alias_method :b, :bottom
98
98
 
99
+ def width
100
+ right + left
101
+ end
102
+
103
+ def height
104
+ top + bottom
105
+ end
106
+
99
107
  def self.convert(value)
100
108
  case value
101
109
  when String
@@ -240,31 +248,184 @@ module Hokusai
240
248
  end
241
249
  end
242
250
 
243
- class Embedded
244
- attr_reader :raw
251
+ class Touch
252
+ attr_accessor :stack, :archive
253
+ def initialize
254
+ @stack = []
255
+ @archive = []
256
+ @tapped = false
257
+ @swiped = false
258
+ @pinched = false
259
+ # @file = File.open("touch.log", "w")
260
+ end
261
+
262
+ def tapped?
263
+ @tapped
264
+ end
265
+
266
+ def swiped?
267
+ @swiped
268
+ end
269
+
270
+ def pinched?
271
+ @pinched
272
+ end
273
+
274
+ def longtapping?(stuff = "ok")
275
+ log("#{touching?} - #{elapsed(token)} - #{stuff}") if touching?
276
+ touching? && elapsed(token) > 5
277
+ end
245
278
 
246
- [
247
- :hold, :hold_duration, :drag, :drag_direction,
248
- :drag_pos, :drag_angle, :pinch,
249
- :pinch_direction, :pinch_pos, :pinch_angle
250
- ].each do |key|
251
- define_method(key) do
252
- raw[key]
279
+ def longtapped?
280
+ @longtapped
281
+ end
282
+
283
+ def touching?
284
+ type == :down || type == :move
285
+ end
286
+
287
+ def duration
288
+ if longtapping?
289
+ return elapsed(token)
253
290
  end
291
+
292
+ first, last = archive[-2..-1]
254
293
 
255
- define_method("#{key}=") do |val|
256
- raw[key] = val
294
+ last[:start] - first[:start]
295
+ end
296
+
297
+ def distance
298
+ raise Hokusai::Error.new("Archive is empty") if archive.empty?
299
+ first, last = archive[-2..-1]
300
+
301
+ x = last[:x] - first[:x]
302
+ y = last[:y] - first[:y]
303
+
304
+ [x, y]
305
+ end
306
+
307
+ def direction
308
+ raise Hokusai::Error.new("Archive is empty") if archive.empty?
309
+
310
+ first, last = archive[-2..-1]
311
+
312
+ x = last[:x] - first[:x]
313
+ y = last[:y] - first[:y]
314
+
315
+ if x.abs > y.abs
316
+ # swiping left/right
317
+ last[:x] > first[:x] ? :right : :left
318
+ else
319
+ # swiping up/down
320
+ last[:y] > first[:y] ? :down : :up
257
321
  end
258
322
  end
259
323
 
324
+ def angle
325
+ raise Hokusai::Error.new("Archive is empty") if archive.empty?
260
326
 
261
- def initialize(raw)
262
- @raw = raw
327
+ last, first = archive[-2..-1]
328
+
329
+ x = last[:x] - first[:x]
330
+ y = last[:y] - first[:y]
331
+
332
+ (Math.atan2(x, y) * (-180 / Math::PI)).round(0).to_i
333
+ end
334
+
335
+ def log(str)
336
+ # Thread.new do
337
+ # @file.write_nonblock("#{str}\n")
338
+ # end
339
+ end
340
+
341
+ def record(finger, x, y)
342
+ log("recording #{token}")
343
+ if type == :down
344
+ push(:move, finger, x, y)
345
+ log("state is move")
346
+ elsif type == :move
347
+ stack.last[:x] = x
348
+ stack.last[:y] = y
349
+
350
+ log("updated state move")
351
+ else
352
+ @longtapped = false
353
+ @swiped = false
354
+ @tapped = false
355
+ push(:down, finger, x, y)
356
+ log("state is down")
357
+ end
358
+ end
359
+
360
+ def clear
361
+ log("clearing")
362
+ if type == :move
363
+ log("elapsed: #{elapsed(token)}")
364
+ if elapsed(token) > 0.05 && within(10.0)
365
+ @longtapped = true
366
+ log('longtap')
367
+ else
368
+ @swiped = true
369
+ log('swipe')
370
+ end
371
+ elsif type == :down
372
+ @tapped = true
373
+ log('tap')
374
+ else
375
+ @longtapped = false
376
+ @swiped = false
377
+ @tapped = false
378
+ end
379
+
380
+ self.archive = stack.dup
381
+ stack.clear
382
+ end
383
+
384
+ def elapsed(token)
385
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - token[:start]
386
+ end
387
+
388
+ def within(threshold)
389
+ move = stack.last
390
+ down = stack[-2]
391
+
392
+ t1 = (move[:x] - down[:x]).abs
393
+ t2 = (move[:y] - down[:y]).abs
394
+
395
+ t1 < threshold && t2 < threshold
396
+ end
397
+
398
+ def pop
399
+ stack.pop
400
+ end
401
+
402
+ def push(type, finger, x, y)
403
+ log("push: #{type}")
404
+ stack << {
405
+ type: type,
406
+ i: finger,
407
+ x: x,
408
+ y: y,
409
+ start: Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
410
+ }
411
+ end
412
+
413
+ def index
414
+ token&.[](:finger)
415
+ end
416
+
417
+ def type
418
+ token&.[](:type)
419
+ end
420
+
421
+ def token
422
+ @stack.last
263
423
  end
264
424
  end
265
425
 
266
426
  class Input
267
- attr_reader :raw
427
+ attr_accessor :keyboard_override
428
+ attr_reader :raw, :touch
268
429
 
269
430
  def hash
270
431
  [self.class, mouse.pos.x, mouse.pos.y, mouse.scroll, mouse.left.clicked, mouse.left.down, mouse.left.up].hash
@@ -272,12 +433,14 @@ module Hokusai
272
433
 
273
434
  def initialize(raw)
274
435
  @raw = raw
436
+ @touch = nil
437
+ @keyboard_override = false
275
438
  end
276
439
 
277
- def embedded
278
- return nil if @raw[:embedded].null?
440
+ def support_touch!
441
+ @touch ||= Touch.new
279
442
 
280
- Embedded.new(@raw[:embedded])
443
+ self
281
444
  end
282
445
 
283
446
  def keyboard
@@ -0,0 +1,197 @@
1
+ require "rouge"
2
+ require "hokusai"
3
+ require_relative "./lib/hokusai_code/formatter"
4
+
5
+ module Hokusai::Util
6
+ class Wrapped
7
+ attr_accessor :text, :x, :y, :extra
8
+
9
+ def initialize(text, x, y, extra)
10
+ @text = text
11
+ @x = x
12
+ @y = y
13
+ @extra = extra
14
+ end
15
+ end
16
+
17
+ class SelectionWrapper
18
+ attr_accessor :x, :y, :width, :height
19
+
20
+ def initialize(x, y, w, h)
21
+ @x = x
22
+ @y = y
23
+ @width = w
24
+ @height = h
25
+ end
26
+
27
+ def <<(w)
28
+ @width += w
29
+ end
30
+ end
31
+
32
+ class WrapStream
33
+ attr_accessor :width, :current_width, :x, :y,
34
+ :origin_x, :origin_y, :buffer, :stack
35
+ attr_reader :on_text_cb, :on_text_selection_cb, :on_advancex_cb, :selector, :padding
36
+
37
+ def initialize(width, &measure)
38
+ @width = width
39
+ @current_width = 0.0
40
+
41
+ @origin_x = 0.0
42
+ @origin_y = 0.0
43
+ @x = @origin_x
44
+ @y = @origin_y
45
+
46
+ @stack = []
47
+ @buffer = ""
48
+
49
+ @measure_cb = measure
50
+ end
51
+
52
+ def on_advancex(&block)
53
+ @on_advancex_cb = block
54
+ end
55
+
56
+ def on_text_selection(selector, padding, &block)
57
+ @selector = selector
58
+ @padding = padding || Hokusai::Padding.new(0.0, 0.0, 0.0, 0.0)
59
+ @on_text_selection_cb = block
60
+ end
61
+
62
+ def on_text(&block)
63
+ @on_text_cb = block
64
+ end
65
+
66
+ def measure(string, extra)
67
+ @measure_cb.call(string, extra)
68
+ end
69
+
70
+ def flush
71
+ sx = x + padding.left
72
+ wrapper = nil
73
+ stack.each do |(range, extra)|
74
+ str = buffer[range]
75
+ if selector
76
+ str.split("").each do |char|
77
+ nw, nh = measure(char, extra)
78
+ ox = on_advancex_cb.call(char.codepoints.first)
79
+
80
+ if selector.selected(sx, y + padding.top - selector.offset_y, nw, nh)
81
+ wrapper ||= SelectionWrapper.new(sx, y + padding.top, 0.0, nh)
82
+ wrapper << ox
83
+ end
84
+
85
+ sx += ox
86
+ end
87
+
88
+ on_text_selection_cb.call(wrapper) if wrapper
89
+ wrapper = nil
90
+ end
91
+
92
+ nw, _ = measure(str, extra)
93
+
94
+ # hard break on the buffer, split on character
95
+ wrap_and_call(str, extra)
96
+
97
+ self.x += nw
98
+ end
99
+
100
+ self.current_width = 0.0
101
+ self.buffer = ""
102
+ stack.clear
103
+ self.x = origin_x
104
+ end
105
+
106
+ def wrap(text, extra)
107
+ offset = 0
108
+ size = text.size
109
+
110
+ stack << [((buffer.size)..(text.size + buffer.size - 1)), extra]
111
+
112
+ while offset < size
113
+ char = text[offset]
114
+ w, h = measure(char, extra)
115
+
116
+ # if it's a newline we want to break
117
+ if char =~ /\n|\r\n/
118
+ flush
119
+
120
+ stack << [(0...(text.size - offset - 1)), extra]
121
+ self.y += h
122
+ self.x = origin_x
123
+ offset += 1
124
+
125
+ next
126
+ end
127
+
128
+ # if adding this char extends beyond the boundary
129
+ if current_width + w > width
130
+ # find the last space
131
+ idx = buffer.rindex(" ")
132
+
133
+ # if there is a break in this line split the buffer
134
+ # and render the current line
135
+ unless idx.nil? || idx < (buffer.size / 2)
136
+ cur = []
137
+ nex = []
138
+ found = false
139
+
140
+ # We need to split up both the buffer, and the ranges
141
+ while payload = stack.shift
142
+ range, xtra = payload
143
+ if range.include?(idx)
144
+ # putting the space on this line
145
+ cur << [(range.begin..idx), xtra]
146
+ # pp [range, idx]
147
+ nex << [(0..(range.end - idx - 1)), xtra] unless idx == range.end
148
+
149
+ found = true
150
+ elsif !found
151
+ cur << payload
152
+ else
153
+ nex << [((range.begin - idx - 1)..(range.end - idx - 1)), xtra]
154
+ end
155
+ end
156
+
157
+ scur = buffer[0..idx]
158
+ snex = buffer[(idx + 1)..-1]
159
+
160
+ cur.each do |(range, xtra)|
161
+ str = scur[range]
162
+
163
+ nw, _ = measure(str, xtra)
164
+ wrap_and_call(str, xtra)
165
+
166
+ self.x += nw
167
+ end
168
+
169
+ self.buffer = snex + char
170
+ self.stack = nex
171
+ self.y += h
172
+ self.current_width = measure(buffer, extra).first
173
+ self.x = origin_x
174
+ else
175
+ # break on this word
176
+ flush
177
+
178
+ self.y += h
179
+ self.current_width = measure(char, extra).first
180
+ self.buffer = char
181
+ stack << [(0...(text.size - offset)), extra]
182
+ end
183
+ else
184
+ self.current_width += w
185
+ buffer << char
186
+ end
187
+
188
+ offset += 1
189
+ end
190
+
191
+ end
192
+
193
+ private def wrap_and_call(text, extra)
194
+ on_text_cb.call Wrapped.new(text, x, y, extra)
195
+ end
196
+ end
197
+ end