hokusai-zero 0.1.4 → 0.1.6

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.
@@ -30,6 +30,10 @@ module Hokusai
30
30
  @provides ||= {}
31
31
  end
32
32
 
33
+ def self.injectables
34
+ @injectables ||= []
35
+ end
36
+
33
37
  # Sets the template for this block
34
38
  #
35
39
  # @param [String] template to set
@@ -118,16 +122,18 @@ module Hokusai
118
122
  end
119
123
 
120
124
  def self.inject(name, aliased = name)
125
+ injectables << name
126
+
121
127
  define_method(aliased) do
122
- if provider = Node.provides[node.uuid]&.[](name)
123
- provider.call
124
- end
128
+ @injections[name]&.call
125
129
  end
126
130
  end
127
131
 
128
132
  def self.inject!(name, aliased)
133
+ injectables << name
134
+
129
135
  define_method(aliased) do
130
- if provider = Node.provides[node.uuid]&.[](name)
136
+ if provider = @injections[name]
131
137
  return provider.call
132
138
  end
133
139
 
@@ -147,6 +153,25 @@ module Hokusai
147
153
  raise Hokusai::Error.new("Must supply node argument to #{self.class}.new") unless args[:node]
148
154
 
149
155
  @node = args[:node]
156
+ @injections = {}
157
+
158
+ self.class.injectables.each do |name|
159
+ if value = args[:providers][name]
160
+ @injections[name] = value
161
+ end
162
+ end
163
+ end
164
+
165
+ def providers
166
+ self.class.provides.map do |k, v|
167
+ if v.is_a?(Symbol)
168
+ [k, -> { public_send(v) }]
169
+ elsif v.is_a?(Proc)
170
+ [k, v]
171
+ else
172
+ [k, -> { v }]
173
+ end
174
+ end.to_h
150
175
  end
151
176
 
152
177
  def children?
@@ -179,23 +204,23 @@ module Hokusai
179
204
 
180
205
  def draw(&block)
181
206
  instance_eval(&block)
182
- # node.meta.commands.each(&:draw)
183
- # node.meta.commands.clear!
184
207
  end
185
208
 
186
209
  def method_missing(name, *args,**kwargs, &block)
187
- if Hokusai::Meta.commands.respond_to?(name)
188
- return Hokusai::Meta.commands.send(name, *args, **kwargs, &block)
210
+ if node.meta.commands.respond_to?(name)
211
+ return node.meta.commands.send(name, *args, **kwargs, &block)
189
212
  end
190
213
 
191
214
  super
192
215
  end
193
216
 
194
217
  def draw_with
195
- yield Hokusai::Meta.commands
218
+ yield node.meta.commands
219
+ end
196
220
 
197
- # node.meta.commands.each(&:draw)
198
- # node.meta.commands.clear!
221
+ def execute_draw
222
+ node.meta.commands.execute
223
+ node.meta.commands.clear!
199
224
  end
200
225
 
201
226
  def render(canvas)
@@ -9,7 +9,7 @@ class Hokusai::Blocks::Cursor < Hokusai::Block
9
9
  computed :x, default: 0.0
10
10
  computed :y, default: 0.0
11
11
  computed :show, default: false
12
- computed :speed, default: 0.1
12
+ computed :speed, default: 0.5
13
13
  computed :cursor_width, default: 2.0
14
14
  computed :cursor_height, default: 0.0
15
15
  computed :color, default: DEFAULT_COLOR, convert: Hokusai::Color
@@ -0,0 +1,205 @@
1
+ class Hokusai::Blocks::DropDownItem < Hokusai::Block
2
+ style <<~EOF
3
+ [style]
4
+ cursorStyle {
5
+ cursor: "pointer";
6
+ }
7
+ EOF
8
+
9
+ template <<~EOF
10
+ [template]
11
+ text {
12
+ @hover="hover_handler"
13
+ @mouseout="mouseout_handler"
14
+ ...cursorStyle
15
+ :content="option"
16
+ :color="color"
17
+ :size="size"
18
+ @click="emit_option"
19
+ @height_updated="update_height"
20
+ }
21
+ EOF
22
+
23
+ uses(text: Hokusai::Blocks::Text)
24
+
25
+ computed! :index
26
+ computed! :option
27
+ computed! :size
28
+ computed! :color
29
+
30
+ attr_accessor :hovered
31
+
32
+ def hover_handler(event)
33
+ self.hovered = true
34
+ end
35
+
36
+ def mouseout_handler(event)
37
+ self.hovered = false
38
+ end
39
+
40
+ def update_height(height)
41
+ node.meta.set_prop(:height, height)
42
+
43
+ emit("height", index, height)
44
+ end
45
+
46
+ def emit_option(event)
47
+ emit("option", index)
48
+ end
49
+
50
+ def render(canvas)
51
+ if hovered
52
+ draw do
53
+ rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
54
+ command.color = Hokusai::Color.new(255, 255, 255, 20)
55
+ end
56
+ end
57
+ end
58
+
59
+ yield canvas
60
+ end
61
+ end
62
+
63
+ class Hokusai::Blocks::Dropdown < Hokusai::Block
64
+ style <<~EOF
65
+ [style]
66
+ panelStyle {
67
+ z: 1;
68
+ }
69
+ rootStyle {
70
+ height: 70.0;
71
+ color: rgb(122, 118, 135);
72
+ }
73
+
74
+ cursorStyle {
75
+ cursor: "pointer";
76
+ }
77
+ EOF
78
+
79
+ template <<~EOF
80
+ [template]
81
+ vblock {
82
+ @hover="dropdown_hover"
83
+ @mouseout="dropdown_mouseout"
84
+ @click="dropdown_toggle"
85
+ :background="background"
86
+ :height="size_with_padding"
87
+ :outline="outline"
88
+ :outline_color="outline_color"
89
+ }
90
+ hblock
91
+ label {
92
+ ...cursorStyle
93
+ :content="dropdown_option_selected"
94
+ :size="size"
95
+ :color="text_color"
96
+ }
97
+ image {
98
+ padding="5.0,10.0,5.0,5.0"
99
+ :source="dropdown_icon"
100
+ :height="size"
101
+ :width="size"
102
+ }
103
+ [if="dropdown_is_toggled"]
104
+ panel#first {
105
+ ...panelStyle
106
+ :height="panel_height"
107
+ :background="background"
108
+ }
109
+ [for="option in options"]
110
+ dropdown_item {
111
+ :color="text_color"
112
+ :size="size"
113
+ :height="option_height(index)"
114
+ :option="option_content(option)"
115
+ :key="dropdown_key(option, index)"
116
+ :index="index"
117
+ @option="option_emit_selected"
118
+ @height="option_update_height"
119
+ }
120
+ EOF
121
+
122
+ uses(
123
+ vblock: Hokusai::Blocks::Vblock,
124
+ hblock: Hokusai::Blocks::Hblock,
125
+ label: Hokusai::Blocks::Text,
126
+ panel: Hokusai::Blocks::Panel,
127
+ image: Hokusai::Blocks::Image,
128
+ dropdown_item: Hokusai::Blocks::DropDownItem
129
+ )
130
+
131
+ computed! :options
132
+ computed :option_callback, default: ->(option) { option }
133
+ computed :size, default: 25, convert: proc(&:to_i)
134
+ computed :padding, default: Hokusai::Padding.new(5.0, 5.0, 5.0, 5.0), convert: Hokusai::Padding
135
+ computed :background, default: Hokusai::Color.new(67, 64, 92), convert: Hokusai::Color
136
+ computed :outline, default: Hokusai::Outline.new(0.0, 0.0, 1.0, 0.0), convert: Hokusai::Outline
137
+ computed :outline_color, default: Hokusai::Color.new(122, 118, 135), convert: Hokusai::Color
138
+ computed :text_color, default: Hokusai::Color.new(255, 255, 255), convert: Hokusai::Color
139
+ computed :panel_width, default: 200.0, convert: proc(&:to_f)
140
+ computed :panel_height, default: 300.0, convert: proc(&:to_f)
141
+ computed :icon, default: "#{ASSETS_FOLDER}/arrow-drop-down-line.png"
142
+
143
+ attr_accessor :selected, :dropdown_is_toggled, :hovered
144
+ attr_reader :heights
145
+
146
+ def dropdown_icon
147
+ icon
148
+ end
149
+
150
+ def dropdown_hover(event)
151
+ self.hovered = true
152
+ end
153
+
154
+ def dropdown_mouseout(event)
155
+ self.hovered = false
156
+ end
157
+
158
+ def size_with_padding
159
+ size + padding.top + padding.bottom
160
+ end
161
+
162
+ def dropdown_key(option, index)
163
+ "option-#{option_callback.call(option)}-#{index}"
164
+ end
165
+
166
+ def dropdown_toggle(event)
167
+ self.dropdown_is_toggled = !dropdown_is_toggled
168
+ end
169
+
170
+ def dropdown_option_selected
171
+ option_callback.call(selected)
172
+ end
173
+
174
+ def option_height(index)
175
+ heights[index]
176
+ end
177
+
178
+ def option_update_height(index, height)
179
+ heights[index] = height
180
+ end
181
+
182
+ def option_content(option)
183
+ option_callback.call(option)
184
+ end
185
+
186
+ def after_updated
187
+ node.meta.set_prop(:height, size * 2)
188
+ end
189
+
190
+ def option_emit_selected(index)
191
+ emit("selected", options[index])
192
+
193
+ self.selected = options[index]
194
+ self.dropdown_is_toggled = false
195
+ end
196
+
197
+ def initialize(**args)
198
+ super
199
+
200
+ @hovered = false
201
+ @heights = {}
202
+ @dropdown_is_toggled = false
203
+ @selected = options.first
204
+ end
205
+ end
@@ -9,12 +9,13 @@ class Hokusai::Blocks::Image < Hokusai::Block
9
9
  computed! :source
10
10
  computed :width, default: nil
11
11
  computed :height, default: nil
12
+ computed :padding, default: Hokusai::Padding.new(0.0, 0.0, 0.0, 0.0), convert: Hokusai::Padding
12
13
 
13
14
  def render(canvas)
14
15
  src = Pathname.new(source).absolute? ? source : "#{File.dirname(caller[-1].split(":")[0])}/#{source}"
15
16
 
16
17
  draw do
17
- image(src, canvas.x, canvas.y, width&.to_f || canvas.width, height&.to_f || canvas.height)
18
+ image(src, canvas.x + padding.left, canvas.y + padding.top, (width&.to_f || canvas.width) - padding.right, (height&.to_f || canvas.height) - padding.bottom)
18
19
  end
19
20
 
20
21
  yield canvas
@@ -195,7 +195,7 @@ class Hokusai::Blocks::Input < Hokusai::Block
195
195
  flush
196
196
 
197
197
  if table.pieces.size > 10
198
- self.table = Util::PieceTable.new(table.to_s)
198
+ self.table = ::Hokusai::Util::PieceTable.new(table.to_s)
199
199
  end
200
200
 
201
201
  self.start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -0,0 +1,62 @@
1
+ class Hokusai::Blocks::Modal < Hokusai::Block
2
+ style <<~EOF
3
+ [style]
4
+ closeButtonStyle {
5
+ width: 40;
6
+ height: 40;
7
+ cursor: "pointer";
8
+ padding: padding(10.0, 10.0, 10.0, 0.0)
9
+ }
10
+ EOF
11
+
12
+ template <<~EOF
13
+ [template]
14
+ hblock
15
+ empty
16
+ empty
17
+ image {
18
+ :source="close_icon"
19
+ ...closeButtonStyle
20
+ @click="emit_close"
21
+
22
+ }
23
+ hblock
24
+ empty
25
+ slot
26
+ empty
27
+ hblock
28
+ empty
29
+ EOF
30
+
31
+ uses(
32
+ vblock: Hokusai::Blocks::Vblock,
33
+ hblock: Hokusai::Blocks::Hblock,
34
+ empty: Hokusai::Blocks::Empty,
35
+ image: Hokusai::Blocks::Image
36
+ )
37
+
38
+ computed :active, default: false
39
+ computed :background, default: [0, 0, 0, 200], convert: Hokusai::Color
40
+ computed :close_icon, default: "#{ASSETS_FOLDER}/close-large-line.png"
41
+
42
+ def emit_close(event)
43
+ emit("close")
44
+ end
45
+
46
+ def on_mounted
47
+ node.meta.set_prop(:z, 1)
48
+ node.meta.set_prop(:ztarget, "root")
49
+ end
50
+
51
+ def render(canvas)
52
+ return unless active
53
+
54
+ draw do
55
+ rect(canvas.x, canvas.y, canvas.width, canvas.height) do |command|
56
+ command.color = background
57
+ end
58
+ end
59
+
60
+ yield canvas
61
+ end
62
+ end
@@ -62,8 +62,8 @@ class Hokusai::Blocks::Panel < Hokusai::Block
62
62
  if y = top
63
63
  if new_scroll_y < y
64
64
  self.scroll_goto_y = y
65
- elsif new_scroll_y > panel_height
66
- self.scroll_goto_y = panel_height
65
+ elsif new_scroll_y - top >= panel_height
66
+ self.scroll_goto_y = panel_height if scroll_percent != 1.0
67
67
  else
68
68
  self.scroll_goto_y = new_scroll_y
69
69
  end
@@ -50,8 +50,6 @@ class Hokusai::Blocks::Scrollbar < Hokusai::Block
50
50
  else
51
51
  self.scrolling = false
52
52
  end
53
-
54
- # event.stop
55
53
  end
56
54
 
57
55
  def scroll_top_height
@@ -15,6 +15,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
15
15
  uses(empty: Hokusai::Blocks::Empty)
16
16
 
17
17
  computed! :content
18
+ computed :cursor, default: nil
18
19
  computed :font, default: nil
19
20
  computed :size, default: 16, convert: proc(&:to_i)
20
21
  computed :line_height, default: 5, convert: proc(&:to_f)
@@ -68,7 +69,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
68
69
  iterator.on_draw do |text, x, y, group|
69
70
  if selector = selection
70
71
  if cursor_offset&.zero? && !selector.started
71
- selector.cursor = [x, y + offset_y, 0.0, size.to_f]
72
+ # selector.cursor = [x, y + offset_y, 0.0, size.to_f]
72
73
 
73
74
  self.last_cursor_offset = cursor_offset
74
75
  end
@@ -112,6 +113,8 @@ class Hokusai::Blocks::Text < Hokusai::Block
112
113
  system("open #{group.link}")
113
114
  when /linux/
114
115
  system("xdg-open #{group.link}")
116
+ when /msys|mingw/
117
+ system("Start-Process \"#{group.link}\"")
115
118
  end
116
119
 
117
120
  self.click_position = nil
@@ -125,9 +128,9 @@ class Hokusai::Blocks::Text < Hokusai::Block
125
128
  end
126
129
 
127
130
  iterator.on_draw_selection do |x, y, width, height|
128
- # commands.rect(x, y, width, height) do |command|
129
- # command.color = selection_color
130
- # end
131
+ commands.rect(x, y, width, height) do |command|
132
+ command.color = selection_color
133
+ end
131
134
  end
132
135
 
133
136
  iterator.on_selection_change do |start, stop|
@@ -170,7 +173,7 @@ class Hokusai::Blocks::Text < Hokusai::Block
170
173
  end
171
174
  end
172
175
 
173
- if link_hovered
176
+ if link_hovered || cursor == "pointer"
174
177
  Hokusai.set_mouse_cursor(:pointer)
175
178
  elsif hovered
176
179
  Hokusai.set_mouse_cursor(:ibeam)
@@ -15,7 +15,9 @@ module Hokusai
15
15
  class Commands
16
16
  attr_reader :queue
17
17
 
18
- def initialize; end
18
+ def initialize
19
+ @queue = []
20
+ end
19
21
 
20
22
  # Draw a rectangle
21
23
  #
@@ -28,7 +30,8 @@ module Hokusai
28
30
 
29
31
  yield(command)
30
32
 
31
- command.draw
33
+ queue << command
34
+ # command.draw
32
35
  end
33
36
 
34
37
  # Draw a circle
@@ -41,7 +44,9 @@ module Hokusai
41
44
 
42
45
  yield(command)
43
46
 
44
- command.draw
47
+
48
+ queue << command
49
+ # command.draw
45
50
  end
46
51
 
47
52
  # Draws an SVG
@@ -55,23 +60,25 @@ module Hokusai
55
60
  command = Commands::SVG.new(source, x, y, w, h)
56
61
 
57
62
  yield(command)
63
+
64
+ queue << command
58
65
  end
59
66
 
60
67
  # Invokes an image command
61
68
  # from a filename, at position {x,y} with `w`x`h` dimensions
62
69
  def image(source, x, y, w, h)
63
- Commands::Image.new(source, x, y, w, h).draw
70
+ queue << Commands::Image.new(source, x, y, w, h)
64
71
  end
65
72
 
66
73
  # Invokes a scissor begin command
67
74
  # at position {x,y} with `w`x`h` dimensions
68
75
  def scissor_begin(x, y, w, h)
69
- Commands::ScissorBegin.new(x, y, w, h).draw
76
+ queue << Commands::ScissorBegin.new(x, y, w, h)
70
77
  end
71
78
 
72
79
  # Invokes a scissor stop command
73
80
  def scissor_end
74
- Commands::ScissorEnd.new.draw
81
+ queue << Commands::ScissorEnd.new
75
82
  end
76
83
 
77
84
  # Draws text
@@ -83,7 +90,15 @@ module Hokusai
83
90
  command = Commands::Text.new(content, x, y)
84
91
  yield command
85
92
 
86
- command.draw
93
+ queue << command
94
+ end
95
+
96
+ def execute
97
+ queue.each(&:draw)
98
+ end
99
+
100
+ def clear!
101
+ queue.clear
87
102
  end
88
103
  end
89
104
  end
@@ -224,7 +224,7 @@ module Hokusai
224
224
  end
225
225
 
226
226
  def char_is_selected(char)
227
- return false if select_begin.nil? || select_end.nil?
227
+ return false if select_begin.nil? || select_end.nil? || (select_end - select_begin).zero?
228
228
 
229
229
  (select_begin..select_end).include?(char.offset)
230
230
  end
@@ -5,7 +5,7 @@ module Hokusai
5
5
  attr_reader :focused, :parent, :target, :updater,
6
6
  :props, :publisher
7
7
 
8
- def self.commands
8
+ def commands
9
9
  @commands ||= Commands.new
10
10
  end
11
11
 
@@ -126,13 +126,6 @@ module Hokusai
126
126
 
127
127
  false
128
128
  end
129
- #
130
- # def destroy
131
- # children.each do |child|
132
- # child.before_destroy if child.respond_to?(:before_destroy)
133
- # child.node.destroy
134
- # end
135
- # end
136
129
 
137
130
  def child_delete(index)
138
131
  if child = children![index]
@@ -27,7 +27,7 @@ module Hokusai
27
27
 
28
28
  INDEX_KEY = "index".freeze
29
29
 
30
- def_delegators :@entry, :ast, :block, :target, :parent
30
+ def_delegators :@entry, :ast, :block, :target, :parent, :providers
31
31
 
32
32
  def initialize(mount_entry)
33
33
  @entry = mount_entry
@@ -78,12 +78,12 @@ module Hokusai
78
78
  block.node.meta << child_block
79
79
 
80
80
  node.ast.children.each_with_index do |child, idx|
81
- entries_to_return << MountEntry.new(index, child, child_block, child_block, child_block, context: nil)
81
+ entries_to_return << MountEntry.new(index, child, child_block, child_block, child_block, context: nil, providers: providers.merge(child_block.providers))
82
82
  end
83
83
 
84
84
  siblings = []
85
85
  portal.ast.children.each_with_index do |child, idx|
86
- siblings << MountEntry.new(idx, child, child_block, child_block, target, context: ctx)
86
+ siblings << MountEntry.new(idx, child, child_block, child_block, target, context: ctx, providers: providers.merge(child_block.providers))
87
87
  end
88
88
 
89
89
  secondary_entries << siblings
@@ -1,14 +1,15 @@
1
1
  module Hokusai
2
2
  module Mounting
3
3
  class MountEntry
4
- attr_reader :block, :parent, :ast, :target, :index, :ctx
4
+ attr_reader :block, :parent, :ast, :target, :index, :ctx, :providers
5
5
 
6
- def initialize(index, ast, block, parent, target = parent, context: nil)
6
+ def initialize(index, ast, block, parent, target = parent, context: nil, providers: {})
7
7
  @index = index
8
8
  @ast = ast
9
9
  @block = block
10
10
  @parent = parent
11
11
  @target = target
12
+ @providers = providers
12
13
  @ctx = context
13
14
  end
14
15
 
@@ -28,6 +29,7 @@ module Hokusai
28
29
  StringIO.open do |io|
29
30
  io << "#{block.class} | #{ast.type} (#{index})\n"
30
31
  io << "#{block.node.ast.children.map(&:type)}"
32
+ io << "providers: #{providers.map {|k,v| k }.join(", ")}\n"
31
33
  io << "parent: #{parent.class}\n"
32
34
  io << "target: #{target.class}\n\n"
33
35
  end.string
@@ -35,7 +37,7 @@ module Hokusai
35
37
 
36
38
  def with_block(new_block, supercede_parent: false)
37
39
  parent_block = supercede_parent ? block : parent
38
- MountEntry.new(index, ast, new_block, parent_block, target, context: ctx)
40
+ MountEntry.new(index, ast, new_block, parent_block, target, context: ctx, providers: providers)
39
41
  end
40
42
 
41
43
  def mount(context: nil)
@@ -46,23 +48,11 @@ module Hokusai
46
48
  node.add_styles(target.class)
47
49
  node.add_props_from_block(target, context: context || ctx)
48
50
 
49
- child_block = klass.new(node: node)
51
+ # handle provides / dependency injection
52
+ child_block = klass.new(node: node, providers: providers)
50
53
  child_block.node.meta.publisher.add(target) # todo
51
54
  UpdateEntry.new(child_block, block, target).register(context: context || ctx)
52
55
 
53
- block.class.provides.each do |k, v|
54
- if v.is_a?(Symbol)
55
- Node.provide(child_block.node, k, ->{ block.public_send(v) })
56
-
57
- # child_block.node.meta.provides[k] = -> { block.public_send(v) }
58
- # child_block.class.provides[k] = -> { block.public_send(v) }
59
- else
60
- Node.provide(child_block.node, k, v)
61
- # child_block.node.meta.provides[k] = v
62
- # child_block.class.provides[k] = v
63
- end
64
- end
65
-
66
56
  block.node.meta << child_block
67
57
 
68
58
  yield child_block
@@ -12,15 +12,6 @@ module Hokusai
12
12
 
13
13
  def_delegators :@ast, :slot?, :type, :event
14
14
 
15
- def self.provides
16
- @provides ||= {}
17
- end
18
-
19
- def self.provide(node, key, value)
20
- provides[node.uuid] ||= {}
21
- provides[node.uuid][key] = value
22
- end
23
-
24
15
  def self.parse(template, name = "root", parent = nil)
25
16
  ast = Ast.parse(template, name)
26
17