hokusai-zero 0.2.6.pre.pinephone2 → 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
@@ -2,9 +2,9 @@ module Hokusai
2
2
  class TouchEvent < Event
3
3
  extend Forwardable
4
4
 
5
- def_delegators :@touch, :tapped?, :swiped?, :longtapped?, :touching?,
6
- :duration, :direction, :angle, :position, :last_position,
7
- :touch_len, :touch_count, :timer
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
 
@@ -32,14 +32,8 @@ module Hokusai
32
32
  name "taphold"
33
33
 
34
34
  def capture(block, canvas)
35
- if longtapped? && hovered(canvas)
36
- block.node.meta.focus
37
-
38
- if matches(block)
39
- captures << block
40
- end
41
- elsif touching?
42
- block.node.meta.blur
35
+ if matches(block) && longtapped? && hovered(canvas)
36
+ captures << block
43
37
  end
44
38
  end
45
39
  end
@@ -277,7 +277,7 @@ 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
@@ -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
@@ -241,90 +249,183 @@ module Hokusai
241
249
  end
242
250
 
243
251
  class Touch
244
- attr_reader :raw
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
245
261
 
246
- [
247
- :touch_len, :touch_count, :touching_now, :timer,
248
- ].each do |key|
249
- define_method(key) do
250
- raw[:touch][key]
251
- end
262
+ def tapped?
263
+ @tapped
252
264
  end
253
265
 
254
266
  def swiped?
255
- LibHokusai.hoku_input_touch_swiped(raw)
267
+ @swiped
256
268
  end
257
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
278
+
258
279
  def longtapped?
259
- LibHokusai.hoku_input_touch_longtapped(raw)
280
+ @longtapped
281
+ end
282
+
283
+ def touching?
284
+ type == :down || type == :move
260
285
  end
261
286
 
262
- # return [Intger] duration in milliseconds
263
287
  def duration
264
- LibHokusai.hoku_input_touch_duration(raw)
288
+ if longtapping?
289
+ return elapsed(token)
290
+ end
291
+
292
+ first, last = archive[-2..-1]
293
+
294
+ last[:start] - first[:start]
265
295
  end
266
296
 
267
- def touching?
268
- touching_now
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]
269
305
  end
270
306
 
271
- def tapped?
272
- LibHokusai.hoku_input_touch_tapped(raw)
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
321
+ end
273
322
  end
274
323
 
275
- def position(index=0)
276
- touches[index]
324
+ def angle
325
+ raise Hokusai::Error.new("Archive is empty") if archive.empty?
326
+
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
277
333
  end
278
334
 
279
- def last_position(index=0)
280
- last_touches[index]
335
+ def log(str)
336
+ # Thread.new do
337
+ # @file.write_nonblock("#{str}\n")
338
+ # end
281
339
  end
282
340
 
283
- def angle(index = 0)
284
- return nil unless swiped?
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
285
359
 
286
- pos = position(index)
287
- lpos = last_position(index)
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
288
379
 
289
- x = position.x - last_position.x
290
- y = position.y - last_position.y
380
+ self.archive = stack.dup
381
+ stack.clear
382
+ end
291
383
 
292
- (Math.atan2(x, y) * (180 / Math::PI)).round(0).to_i
384
+ def elapsed(token)
385
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - token[:start]
293
386
  end
294
387
 
295
- def direction(index=0)
296
- return nil unless swiped?
388
+ def within(threshold)
389
+ move = stack.last
390
+ down = stack[-2]
297
391
 
298
- pos = position(index)
299
- lpos = last_position(index)
392
+ t1 = (move[:x] - down[:x]).abs
393
+ t2 = (move[:y] - down[:y]).abs
300
394
 
301
- x = position.x - last_position.x
302
- y = position.y - last_position.y
395
+ t1 < threshold && t2 < threshold
396
+ end
303
397
 
304
- if x.abs > y.abs
305
- # swiping left/right
306
- position.x > last_position.x ? :right : :left
307
- else
308
- # swiping up/down
309
- position.y > last_position.y ? :up : :down
310
- end
398
+ def pop
399
+ stack.pop
311
400
  end
312
401
 
313
- def last_touches
314
- @raw[:last_touch_positions].read_array_of_type(LibHokusai::HmlDoubleVec2, :read_pointer, touch_len)
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
+ }
315
411
  end
316
412
 
317
- def touches
318
- @raw[:touch_positions].read_array_of_type(LibHokusai::HmlDoubleVec2, :read_pointer, touch_len)
413
+ def index
414
+ token&.[](:finger)
319
415
  end
320
416
 
321
- def initialize(raw)
322
- @raw = raw
417
+ def type
418
+ token&.[](:type)
419
+ end
420
+
421
+ def token
422
+ @stack.last
323
423
  end
324
424
  end
325
425
 
326
426
  class Input
327
- attr_reader :raw
427
+ attr_accessor :keyboard_override
428
+ attr_reader :raw, :touch
328
429
 
329
430
  def hash
330
431
  [self.class, mouse.pos.x, mouse.pos.y, mouse.scroll, mouse.left.clicked, mouse.left.down, mouse.left.up].hash
@@ -332,12 +433,14 @@ module Hokusai
332
433
 
333
434
  def initialize(raw)
334
435
  @raw = raw
436
+ @touch = nil
437
+ @keyboard_override = false
335
438
  end
336
439
 
337
- def touch
338
- return nil if @raw[:touch].null?
440
+ def support_touch!
441
+ @touch ||= Touch.new
339
442
 
340
- Touch.new(@raw)
443
+ self
341
444
  end
342
445
 
343
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