Class: Zui::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/zui/builder.rb

Constant Summary collapse

UNSET =
Object.new.freeze
CONTAINERS =
%i[
  row column container grid row_layout column_layout grid_layout flow center card
  stack scroll rectangle aspect_ratio constrained_box fitted_box wrap split_view stack_layout loader flickable focus_scope flipable border_image key_catcher
  page pane frame group_box tabs stack_view swipe_view drawer expansion_panel accordion tool_bar popup dialog
  shader_effect shader_effect_source multi_effect rectangular_shadow opacity_mask blur drop_shadow colorize glow
  drag_area drop_area pinch_area hover_area capture_session cursor_surface
].freeze
VALUE_INPUTS =
{
  text_field: :text,
  text_area: :text,
  password_field: :text,
  number_field: :value,
  slider: :value,
  dial: :value,
  spin_box: :value,
  double_spin_box: :value,
  color_picker: :color,
  date_picker: :date,
  time_picker: :time,
  file_picker: :path,
  folder_picker: :path,
  font_picker: :family,
  dropdown: :value,
  searchable_dropdown: :value,
  multi_select: :values,
  button_group: :value,
  radio_group: :value
}.freeze
APP_OPTIONS =
%i[title width height min_width min_height max_width max_height color visible maximized fullscreen].freeze
CHART_COMPONENTS =
%i[
  stacked_bar_chart pie_chart donut_chart scatter_chart bubble_chart radar_chart heatmap
  sparkline gauge radial_gauge histogram candlestick_chart
].freeze
TARGET_ANIMATION_COMPONENTS =
%i[
  number_animation color_animation rotation_animation vector_animation path_animation property_animation
  spring_animation smoothed_animation anchor_animation parent_animation opacity_animator rotation_animator
  scale_animator x_animator y_animator uniform_animator animation_controller behavior transition state_group
  property_changes anchor_changes parent_change
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(application) ⇒ Builder

Returns a new instance of Builder.



35
36
37
38
39
# File 'lib/zui/builder.rb', line 35

def initialize(application)
  @application = application
  @stack = []
  @dynamic_scopes = []
end

Instance Method Details

#accordion(titles = [], id: nil, **props, &block) ⇒ Object



182
183
184
# File 'lib/zui/builder.rb', line 182

def accordion(titles = [], id: nil, **props, &block)
  component(:accordion, id:, titles: Array(titles), **props, &block)
end

#action(label, id: nil, **props, &handler) ⇒ Object



414
415
416
417
418
# File 'lib/zui/builder.rb', line 414

def action(label, id: nil, **props, &handler)
  node = component(:action, id:, text: label.to_s, **props)
  @application.register_handler(node.id, :trigger, handler) if handler
  node
end

#action_button(icon, id: nil, **props, &handler) ⇒ Object



443
444
445
# File 'lib/zui/builder.rb', line 443

def action_button(icon, id: nil, **props, &handler)
  action_component(:action_button, :icon, icon, id:, props:, handler:)
end

#action_group(actions, id: nil, checked: nil, **props) ⇒ Object



419
420
421
422
423
# File 'lib/zui/builder.rb', line 419

def action_group(actions, id: nil, checked: nil, **props)
  action_ids = Array(actions).map { |action_node| action_node.is_a?(Node) ? action_node.id : action_node.to_s }
  checked_id = checked.is_a?(Node) ? checked.id : checked&.to_s
  component(:action_group, id:, action_ids:, checked_action: checked_id, **props)
end

#after(seconds, &block) ⇒ Object



634
# File 'lib/zui/builder.rb', line 634

def after(seconds, &block) = @application.schedule(:after, interval: seconds, &block)

#alert_dialog(title = "", message = "", id: nil, **props) ⇒ Object



219
220
221
# File 'lib/zui/builder.rb', line 219

def alert_dialog(title = "", message = "", id: nil, **props)
  component(:alert_dialog, id:, title: title.to_s, message: message.to_s, **props)
end

#animate(node, properties, duration: 200, easing: :in_out_quad, delay: 0) ⇒ Object



611
612
613
614
615
# File 'lib/zui/builder.rb', line 611

def animate(node, properties, duration: 200, easing: :in_out_quad, delay: 0)
  transition = Animation.new(duration:, easing:, delay:)
  @application.animate(node, properties, transition)
  node
end

#animate_sequence(node, steps) ⇒ Object



617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
# File 'lib/zui/builder.rb', line 617

def animate_sequence(node, steps)
  elapsed = 0
  tracks = steps.flat_map do |step|
    options = step.transform_keys(&:to_sym)
    properties = options.fetch(:to)
    transition = Animation.new(
      duration: options.fetch(:duration, 200),
      easing: options.fetch(:easing, :in_out_quad),
      delay: elapsed + options.fetch(:delay, 0)
    )
    elapsed = transition.delay + transition.duration + options.fetch(:pause, 0)
    @application.animation_tracks(node, properties, transition)
  end
  @application.emit_animation(node, tracks)
  node
end

#animated_image(source, id: nil, **props) ⇒ Object



120
# File 'lib/zui/builder.rb', line 120

def animated_image(source, id: nil, **props) = component(:animated_image, id:, source: source.to_s, **props)

#animation(target: nil, id: nil, **options) ⇒ Object



547
548
549
550
# File 'lib/zui/builder.rb', line 547

def animation(target: nil, id: nil, **options)
  return Animation.new(**options) if target.nil?
  component(:animation, id:, target: node_id(target), **options)
end

#app(name = :main, **options, &block) ⇒ Object

Raises:

  • (ArgumentError)


81
82
83
84
85
# File 'lib/zui/builder.rb', line 81

def app(name = :main, **options, &block)
  unknown = options.keys - APP_OPTIONS
  raise ArgumentError, "unsupported app options: #{unknown.join(', ')}" unless unknown.empty?
  surface(name.to_s, id: "app.#{name}", options:, &block)
end

#application_window(title = "", id: nil, **props, &block) ⇒ Object



134
135
136
# File 'lib/zui/builder.rb', line 134

def application_window(title = "", id: nil, **props, &block)
  component(:application_window, id:, title: title.to_s, **props, &block)
end

#area_chart(values, id: nil, **props) ⇒ Object



497
498
499
# File 'lib/zui/builder.rb', line 497

def area_chart(values, id: nil, **props)
  component(:area_chart, id:, values:, **props)
end

#async(&block) ⇒ Object



636
# File 'lib/zui/builder.rb', line 636

def async(&block) = @application.schedule(:async, &block)

#audio(source, id: nil, **props) ⇒ Object



122
# File 'lib/zui/builder.rb', line 122

def audio(source, id: nil, **props) = component(:audio, id:, source: source.to_s, **props)

#audio_input(id: nil, **props) ⇒ Object



593
# File 'lib/zui/builder.rb', line 593

def audio_input(id: nil, **props) = component(:audio_input, id:, **props)

#audio_output(id: nil, **props) ⇒ Object



594
# File 'lib/zui/builder.rb', line 594

def audio_output(id: nil, **props) = component(:audio_output, id:, **props)

#avatar(source = nil, id: nil, **props) ⇒ Object



123
124
125
# File 'lib/zui/builder.rb', line 123

def avatar(source = nil, id: nil, **props)
  source.nil? ? component(:avatar, id:, **props) : component(:avatar, id:, source: source.to_s, **props)
end

#badge(value = nil, id: nil, **props) ⇒ Object



126
# File 'lib/zui/builder.rb', line 126

def badge(value = nil, id: nil, **props) = component(:badge, id:, value:, **props)


234
235
236
# File 'lib/zui/builder.rb', line 234

def banner(message = "", id: nil, **props)
  component(:banner, id:, message: message.to_s, **props)
end

#bar_chart(values, id: nil, **props) ⇒ Object



501
502
503
# File 'lib/zui/builder.rb', line 501

def bar_chart(values, id: nil, **props)
  component(:bar_chart, id:, values:, **props)
end

#bar_icon_button(icon, id: nil, **props, &handler) ⇒ Object



447
448
449
# File 'lib/zui/builder.rb', line 447

def bar_icon_button(icon, id: nil, **props, &handler)
  action_component(:bar_icon_button, :icon, icon, id:, props:, handler:)
end

#bar_indicator(active_icon, id: nil, **props, &handler) ⇒ Object



451
452
453
# File 'lib/zui/builder.rb', line 451

def bar_indicator(active_icon, id: nil, **props, &handler)
  action_component(:bar_indicator, :active_icon, active_icon, id:, props:, handler:)
end

#bar_widget(&block) ⇒ Object



78
# File 'lib/zui/builder.rb', line 78

def bar_widget(&block) = surface("bar", id: "bar", &block)

#bind(node, property, animation: nil, &reader) ⇒ Object

Raises:

  • (ArgumentError)


539
540
541
542
543
544
545
# File 'lib/zui/builder.rb', line 539

def bind(node, property, animation: nil, &reader)
  raise ArgumentError, "bind requires a node returned by a component method" unless node.is_a?(Node)
  raise ArgumentError, "bind requires a block" unless reader
  transition = normalize_animation(animation)
  @application.register_binding(node, property.to_s, reader, animation: transition)
  node
end

#border_image(source, id: nil, **props, &block) ⇒ Object



130
# File 'lib/zui/builder.rb', line 130

def border_image(source, id: nil, **props, &block) = component(:border_image, id:, source: source.to_s, **props, &block)

#border_overlay(id: nil, **props) ⇒ Object



406
# File 'lib/zui/builder.rb', line 406

def border_overlay(id: nil, **props) = component(:border_overlay, id:, **props)

#bottom_sheet(id: nil, **props, &block) ⇒ Object



225
226
227
# File 'lib/zui/builder.rb', line 225

def bottom_sheet(id: nil, **props, &block)
  component(:bottom_sheet, id:, **props, &block)
end


173
174
175
# File 'lib/zui/builder.rb', line 173

def breadcrumb(items = [], id: nil, **props)
  component(:breadcrumb, id:, items: Array(items), **props)
end

#busy_indicator(running = true, id: nil, **props) ⇒ Object



240
241
242
# File 'lib/zui/builder.rb', line 240

def busy_indicator(running = true, id: nil, **props)
  component(:busy_indicator, id:, running: running, **props)
end

#button(label, id: nil, **props, &handler) ⇒ Object



425
426
427
# File 'lib/zui/builder.rb', line 425

def button(label, id: nil, **props, &handler)
  action_component(:button, :text, label, id:, props:, handler:)
end

#calendar(date = nil, id: nil, **props) ⇒ Object



342
343
344
345
346
# File 'lib/zui/builder.rb', line 342

def calendar(date = nil, id: nil, **props)
  calendar_props = props.dup
  calendar_props[:date] = date.to_s unless date.nil?
  component(:calendar, id:, **calendar_props)
end

#camera(id: nil, **props) ⇒ Object



584
# File 'lib/zui/builder.rb', line 584

def camera(id: nil, **props) = component(:camera, id:, **props)

#canvas(commands = [], id: nil, **props) ⇒ Object



352
353
354
# File 'lib/zui/builder.rb', line 352

def canvas(commands = [], id: nil, **props)
  component(:canvas, id:, commands: Array(commands), **props)
end


341
# File 'lib/zui/builder.rb', line 341

def carousel(items = [], id: nil, **props) = component(:carousel, id:, items: Array(items), **props)

#check_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler) ⇒ Object



279
280
281
282
283
284
285
286
# File 'lib/zui/builder.rb', line 279

def check_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler)
  item_props = props.merge(text: text.to_s)
  item_props[:value] = value unless value.nil?
  item_props[:checked] = checked unless checked.equal?(UNSET)
  node = component(:check_delegate, id:, **item_props)
  @application.register_handler(node.id, :change, handler) if handler
  node
end

#checkbox(label = "", id: nil, checked: UNSET, **props, &handler) ⇒ Object



459
460
461
# File 'lib/zui/builder.rb', line 459

def checkbox(label = "", id: nil, checked: UNSET, **props, &handler)
  input_component(:checkbox, :checked, checked, id:, props: props.merge(label: label.to_s), handler:)
end

#chip(label, id: nil, **props, &handler) ⇒ Object



127
128
129
# File 'lib/zui/builder.rb', line 127

def chip(label, id: nil, **props, &handler)
  action_component(:chip, :text, label, id:, props:, handler:)
end

#circle(radius = 50, id: nil, **props) ⇒ Object



368
369
370
# File 'lib/zui/builder.rb', line 368

def circle(radius = 50, id: nil, **props)
  component(:circle, id:, radius:, **props)
end

#clipboard(text = UNSET, id: nil, **props) ⇒ Object



606
607
608
609
# File 'lib/zui/builder.rb', line 606

def clipboard(text = UNSET, id: nil, **props)
  props = props.merge(text:) unless text.equal?(UNSET)
  component(:clipboard, id:, **props)
end

#close_panel(name = nil) ⇒ Object



641
642
643
# File 'lib/zui/builder.rb', line 641

def close_panel(name = nil)
  @application.emit_effect("close_panel", name.nil? ? {} : { "surface" => name.to_s })
end

#component(type, id: nil, **props, &block) ⇒ Object Also known as: widget, qml_component



41
42
43
44
45
46
47
48
49
50
# File 'lib/zui/builder.rb', line 41

def component(type, id: nil, **props, &block)
  definition = @application.components.fetch(type)
  node = @application.build_node(type, explicit_id: id || scoped_id(type), props:)
  append(node)
  if block
    raise ArgumentError, "#{type} is not a container" unless definition.container
    within(node, &block)
  end
  node
end

#confirm_dialog(message = "", id: nil, **props) ⇒ Object



255
256
257
# File 'lib/zui/builder.rb', line 255

def confirm_dialog(message = "", id: nil, **props)
  component(:confirm_dialog, id:, message: message.to_s, **props)
end

#context_menu(items = [], id: nil, target: nil, **props) ⇒ Object



207
208
209
210
211
212
# File 'lib/zui/builder.rb', line 207

def context_menu(items = [], id: nil, target: nil, **props)
  target_id = target.is_a?(Node) ? target.id : target
  menu_props = props.merge(items: Array(items))
  menu_props[:target] = target_id.to_s unless target_id.nil?
  component(:context_menu, id:, **menu_props)
end

#data_table(rows = [], id: nil, columns: [], **props, &handler) ⇒ Object



328
329
330
331
332
# File 'lib/zui/builder.rb', line 328

def data_table(rows = [], id: nil, columns: [], **props, &handler)
  node = component(:data_table, id:, rows: Array(rows), columns: Array(columns), **props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#day_of_week_row(id: nil, **props) ⇒ Object



349
# File 'lib/zui/builder.rb', line 349

def day_of_week_row(id: nil, **props) = component(:day_of_week_row, id:, **props)

#delay_button(label, id: nil, **props, &handler) ⇒ Object



437
438
439
440
441
# File 'lib/zui/builder.rb', line 437

def delay_button(label, id: nil, **props, &handler)
  node = action_component(:delay_button, :text, label, id:, props: props, handler: nil)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#delegate_model(items = [], id: nil, **props) ⇒ Object



600
# File 'lib/zui/builder.rb', line 600

def delegate_model(items = [], id: nil, **props) = component(:delegate_model, id:, items: Array(items), **props)

#delegate_model_group(items = [], id: nil, **props) ⇒ Object



601
# File 'lib/zui/builder.rb', line 601

def delegate_model_group(items = [], id: nil, **props) = component(:delegate_model_group, id:, items: Array(items), **props)

#dialog(title = "", id: nil, **props, &block) ⇒ Object



216
217
218
# File 'lib/zui/builder.rb', line 216

def dialog(title = "", id: nil, **props, &block)
  component(:dialog, id:, title: title.to_s, **props, &block)
end

#dialog_button_box(buttons = [], id: nil, **props) ⇒ Object



411
412
413
# File 'lib/zui/builder.rb', line 411

def dialog_button_box(buttons = [], id: nil, **props)
  component(:dialog_button_box, id:, buttons: Array(buttons), **props)
end

#divider(id: nil, **props) ⇒ Object



409
# File 'lib/zui/builder.rb', line 409

def divider(id: nil, **props) = component(:divider, id:, **props)

#drawer(id: nil, **props, &block) ⇒ Object



167
168
169
# File 'lib/zui/builder.rb', line 167

def drawer(id: nil, **props, &block)
  component(:drawer, id:, **props, &block)
end

#dynamic(type: :column, id: nil, **props, &renderer) ⇒ Object

Raises:

  • (ArgumentError)


87
88
89
90
91
92
93
94
95
96
# File 'lib/zui/builder.rb', line 87

def dynamic(type: :column, id: nil, **props, &renderer)
  raise ArgumentError, "dynamic requires a block" unless renderer
  definition = @application.components.fetch(type)
  raise ArgumentError, "dynamic component must be a container: #{type}" unless definition.container

  node = component(type, id:, **props)
  within_dynamic(node, &renderer)
  @application.register_structure(node, renderer)
  node
end

#every(seconds, immediate: false, &block) ⇒ Object



635
# File 'lib/zui/builder.rb', line 635

def every(seconds, immediate: false, &block) = @application.schedule(:every, interval: seconds, immediate:, &block)

#expansion_panel(title = "", id: nil, **props, &block) ⇒ Object



179
180
181
# File 'lib/zui/builder.rb', line 179

def expansion_panel(title = "", id: nil, **props, &block)
  component(:expansion_panel, id:, title: title.to_s, **props, &block)
end

#folder_list_model(folder = "", id: nil, **props) ⇒ Object



603
# File 'lib/zui/builder.rb', line 603

def folder_list_model(folder = "", id: nil, **props) = component(:folder_list_model, id:, folder: folder.to_s, **props)

#font_loader(source, id: nil, **props) ⇒ Object



118
# File 'lib/zui/builder.rb', line 118

def font_loader(source, id: nil, **props) = component(:font_loader, id:, source: source.to_s, **props)

#frame(id: nil, **props, &block) ⇒ Object



143
144
145
# File 'lib/zui/builder.rb', line 143

def frame(id: nil, **props, &block)
  component(:frame, id:, **props, &block)
end

#frame_animation(id: nil, **props) ⇒ Object



575
# File 'lib/zui/builder.rb', line 575

def frame_animation(id: nil, **props) = component(:frame_animation, id:, **props)

#gradient(colors = [], id: nil, **props) ⇒ Object



372
373
374
# File 'lib/zui/builder.rb', line 372

def gradient(colors = [], id: nil, **props)
  component(:gradient, id:, colors: Array(colors), **props)
end

#grid_view(items = [], id: nil, **props, &handler) ⇒ Object



310
311
312
313
314
# File 'lib/zui/builder.rb', line 310

def grid_view(items = [], id: nil, **props, &handler)
  node = component(:grid_view, id:, items: Array(items), **props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#group_box(title = "", id: nil, **props, &block) ⇒ Object



146
147
148
# File 'lib/zui/builder.rb', line 146

def group_box(title = "", id: nil, **props, &block)
  component(:group_box, id:, title: title.to_s, **props, &block)
end

#horizontal_header(sections = [], id: nil, **props) ⇒ Object



334
# File 'lib/zui/builder.rb', line 334

def horizontal_header(sections = [], id: nil, **props) = component(:horizontal_header, id:, sections: Array(sections), **props)

#horizontal_header_delegate(text = "", id: nil, **props) ⇒ Object



338
# File 'lib/zui/builder.rb', line 338

def horizontal_header_delegate(text = "", id: nil, **props) = component(:horizontal_header_delegate, id:, text: text.to_s, **props)

#icon(name, id: nil, **props) ⇒ Object



113
# File 'lib/zui/builder.rb', line 113

def icon(name, id: nil, **props) = component(:icon, id:, name: name.to_s, **props)

#image(source, id: nil, **props) ⇒ Object



115
# File 'lib/zui/builder.rb', line 115

def image(source, id: nil, **props) = component(:image, id:, source: source.to_s, **props)

#image_capture(session = nil, id: nil, **props) ⇒ Object



585
586
587
588
# File 'lib/zui/builder.rb', line 585

def image_capture(session = nil, id: nil, **props)
  props = props.merge(session: node_id(session)) unless session.nil?
  component(:image_capture, id:, **props)
end

#item_delegate(text = "", id: nil, value: nil, **props, &handler) ⇒ Object



272
273
274
275
276
277
278
# File 'lib/zui/builder.rb', line 272

def item_delegate(text = "", id: nil, value: nil, **props, &handler)
  item_props = props.merge(text: text.to_s)
  item_props[:value] = value unless value.nil?
  node = component(:item_delegate, id:, **item_props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#label(value = UNSET, id: nil, **props, &reader) ⇒ Object



104
105
106
107
108
# File 'lib/zui/builder.rb', line 104

def label(value = UNSET, id: nil, **props, &reader)
  node = component(:label, id:, **props)
  bind_or_set(node, "text", value, reader)
  node
end

#layout_item_proxy(target, id: nil, **props) ⇒ Object

Raises:

  • (ArgumentError)


401
402
403
404
405
# File 'lib/zui/builder.rb', line 401

def layout_item_proxy(target, id: nil, **props)
  target_id = target.is_a?(Node) ? target.id : target.to_s
  raise ArgumentError, "layout_item_proxy target cannot be empty" if target_id.empty?
  component(:layout_item_proxy, id:, target: target_id, **props)
end

#legend(items = [], id: nil, **props) ⇒ Object



515
# File 'lib/zui/builder.rb', line 515

def legend(items = [], id: nil, **props) = component(:legend, id:, items: Array(items), **props)

#line(x1 = 0, y1 = 0, x2 = 100, y2 = 0, id: nil, **props) ⇒ Object



360
361
362
# File 'lib/zui/builder.rb', line 360

def line(x1 = 0, y1 = 0, x2 = 100, y2 = 0, id: nil, **props)
  component(:line, id:, x1:, y1:, x2:, y2:, **props)
end

#line_chart(values, id: nil, **props) ⇒ Object



493
494
495
# File 'lib/zui/builder.rb', line 493

def line_chart(values, id: nil, **props)
  component(:line_chart, id:, values:, **props)
end

#list_model(items = [], id: nil, **props) ⇒ Object



599
# File 'lib/zui/builder.rb', line 599

def list_model(items = [], id: nil, **props) = component(:list_model, id:, items: Array(items), **props)

#list_view(items = [], id: nil, **props, &handler) ⇒ Object



267
268
269
270
271
# File 'lib/zui/builder.rb', line 267

def list_view(items = [], id: nil, **props, &handler)
  node = component(:list_view, id:, items: Array(items), **props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#markdown(source, id: nil, **props) ⇒ Object



110
# File 'lib/zui/builder.rb', line 110

def markdown(source, id: nil, **props) = component(:markdown, id:, text: source.to_s, **props)

#media_devices(id: nil, **props) ⇒ Object



595
# File 'lib/zui/builder.rb', line 595

def media_devices(id: nil, **props) = component(:media_devices, id:, **props)

#media_player(source = "", id: nil, **props) ⇒ Object



578
# File 'lib/zui/builder.rb', line 578

def media_player(source = "", id: nil, **props) = component(:media_player, id:, source: source.to_s, **props)

#media_recorder(session = nil, id: nil, **props) ⇒ Object



589
590
591
592
# File 'lib/zui/builder.rb', line 589

def media_recorder(session = nil, id: nil, **props)
  props = props.merge(session: node_id(session)) unless session.nil?
  component(:media_recorder, id:, **props)
end


191
192
193
# File 'lib/zui/builder.rb', line 191

def menu(items = [], id: nil, **props)
  component(:menu, id:, items: Array(items), **props)
end


204
205
206
# File 'lib/zui/builder.rb', line 204

def menu_bar(menus = [], id: nil, **props)
  component(:menu_bar, id:, menus: Array(menus), **props)
end


194
195
196
197
198
199
200
# File 'lib/zui/builder.rb', line 194

def menu_item(label = "", id: nil, value: nil, **props, &handler)
  item_props = props.merge(text: label.to_s)
  item_props[:value] = value unless value.nil?
  node = component(:menu_item, id:, **item_props)
  @application.register_handler(node.id, :trigger, handler) if handler
  node
end


201
202
203
# File 'lib/zui/builder.rb', line 201

def menu_separator(id: nil, **props)
  component(:menu_separator, id:, **props)
end

#message_dialog(title = "", message = "", id: nil, **props) ⇒ Object



222
223
224
# File 'lib/zui/builder.rb', line 222

def message_dialog(title = "", message = "", id: nil, **props)
  component(:message_dialog, id:, title: title.to_s, message: message.to_s, **props)
end


228
229
230
# File 'lib/zui/builder.rb', line 228

def modal_sheet(title = "", id: nil, **props, &block)
  component(:modal_sheet, id:, title: title.to_s, **props, &block)
end

#model_view_3d(source, id: nil, **props) ⇒ Object



117
# File 'lib/zui/builder.rb', line 117

def model_view_3d(source, id: nil, **props) = component(:model_view_3d, id:, source: source.to_s, **props)

#month_grid(id: nil, **props) ⇒ Object



347
# File 'lib/zui/builder.rb', line 347

def month_grid(id: nil, **props) = component(:month_grid, id:, **props)


170
171
172
# File 'lib/zui/builder.rb', line 170

def navigation_rail(items = [], id: nil, **props)
  component(:navigation_rail, id:, items: Array(items), **props)
end

#on(target_or_event, event = nil, &handler) ⇒ Object

Raises:

  • (ArgumentError)


522
523
524
525
526
527
528
529
530
531
532
# File 'lib/zui/builder.rb', line 522

def on(target_or_event, event = nil, &handler)
  raise ArgumentError, "on requires a block" unless handler
  if target_or_event.is_a?(Node)
    raise ArgumentError, "on(node, event) requires an event" unless event
    node, event_name = target_or_event, event
  else
    raise ArgumentError, "on must be inside a surface or control" if @stack.empty?
    node, event_name = @stack.last, target_or_event
  end
  @application.register_handler(node.id, event_name, handler)
end

#on_click(&handler) ⇒ Object

Raises:

  • (ArgumentError)


517
518
519
520
# File 'lib/zui/builder.rb', line 517

def on_click(&handler)
  raise ArgumentError, "on_click must be inside a surface or control" if @stack.empty?
  on(@stack.last, :click, &handler)
end

#open_panel(name) ⇒ Object



639
# File 'lib/zui/builder.rb', line 639

def open_panel(name) = @application.emit_effect("open_panel", "surface" => name.to_s)

#optical_glyph(text = "", id: nil, **props) ⇒ Object



261
262
263
# File 'lib/zui/builder.rb', line 261

def optical_glyph(text = "", id: nil, **props)
  component(:optical_glyph, id:, text: text.to_s, **props)
end

#page(title = "", id: nil, **props, &block) ⇒ Object



137
138
139
# File 'lib/zui/builder.rb', line 137

def page(title = "", id: nil, **props, &block)
  component(:page, id:, title: title.to_s, **props, &block)
end

#page_indicator(count, id: nil, **props) ⇒ Object



158
159
160
# File 'lib/zui/builder.rb', line 158

def page_indicator(count, id: nil, **props)
  component(:page_indicator, id:, count:, **props)
end

#pagination(count, id: nil, **props) ⇒ Object



176
177
178
# File 'lib/zui/builder.rb', line 176

def pagination(count, id: nil, **props)
  component(:pagination, id:, count:, **props)
end

#pane(id: nil, **props, &block) ⇒ Object



140
141
142
# File 'lib/zui/builder.rb', line 140

def pane(id: nil, **props, &block)
  component(:pane, id:, **props, &block)
end

#panel(name, &block) ⇒ Object



79
# File 'lib/zui/builder.rb', line 79

def panel(name, &block) = surface(name.to_s, id: "panel.#{name}", &block)

#panel_hero(title = "", id: nil, **props) ⇒ Object



258
259
260
# File 'lib/zui/builder.rb', line 258

def panel_hero(title = "", id: nil, **props)
  component(:panel_hero, id:, title: title.to_s, **props)
end

#parallel_animation(animations = [], id: nil, **props) ⇒ Object



569
570
571
# File 'lib/zui/builder.rb', line 569

def parallel_animation(animations = [], id: nil, **props)
  component(:parallel_animation, id:, animations: normalize_animation_specs(animations), **props)
end

#particle_system(id: nil, **props) ⇒ Object



387
388
389
# File 'lib/zui/builder.rb', line 387

def particle_system(id: nil, **props)
  component(:particle_system, id:, **props)
end

#path(data = "", id: nil, **props) ⇒ Object



364
365
366
# File 'lib/zui/builder.rb', line 364

def path(data = "", id: nil, **props)
  component(:path, id:, data: data.to_s, **props)
end

#pause_animation(duration = 0, id: nil, **props) ⇒ Object



564
# File 'lib/zui/builder.rb', line 564

def pause_animation(duration = 0, id: nil, **props) = component(:pause_animation, id:, duration:, **props)


213
214
215
# File 'lib/zui/builder.rb', line 213

def popup(id: nil, **props, &block)
  component(:popup, id:, **props, &block)
end

#progress(value = UNSET, id: nil, **props) ⇒ Object



483
484
485
# File 'lib/zui/builder.rb', line 483

def progress(value = UNSET, id: nil, **props)
  input_component(:progress, :value, value, id:, props:)
end

#progress_ring(value = UNSET, id: nil, **props) ⇒ Object



243
244
245
246
247
248
249
250
251
# File 'lib/zui/builder.rb', line 243

def progress_ring(value = UNSET, id: nil, **props)
  ring_props = props.dup
  if value.equal?(UNSET)
    ring_props[:indeterminate] = true unless ring_props.key?(:indeterminate)
  else
    ring_props[:value] = value
  end
  component(:progress_ring, id:, **ring_props)
end

#property(name, value = UNSET, &reader) ⇒ Object

Raises:

  • (ArgumentError)


534
535
536
537
# File 'lib/zui/builder.rb', line 534

def property(name, value = UNSET, &reader)
  raise ArgumentError, "property must be inside a control" if @stack.empty?
  bind_or_set(@stack.last, name.to_s, value, reader)
end

#property_action(target, property:, value:, id: nil, **props) ⇒ Object



566
567
568
# File 'lib/zui/builder.rb', line 566

def property_action(target, property:, value:, id: nil, **props)
  component(:property_action, id:, target: node_id(target), property: property.to_s, value:, **props)
end

#radio_button(label = "", id: nil, checked: UNSET, **props, &handler) ⇒ Object



463
464
465
# File 'lib/zui/builder.rb', line 463

def radio_button(label = "", id: nil, checked: UNSET, **props, &handler)
  input_component(:radio_button, :checked, checked, id:, props: props.merge(label: label.to_s), handler:)
end

#radio_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler) ⇒ Object



287
288
289
290
291
292
293
294
# File 'lib/zui/builder.rb', line 287

def radio_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler)
  item_props = props.merge(text: text.to_s)
  item_props[:value] = value unless value.nil?
  item_props[:checked] = checked unless checked.equal?(UNSET)
  node = component(:radio_delegate, id:, **item_props)
  @application.register_handler(node.id, :select, handler) if handler
  node
end

#range_slider(lower, upper, id: nil, **props, &handler) ⇒ Object



487
488
489
490
491
# File 'lib/zui/builder.rb', line 487

def range_slider(lower, upper, id: nil, **props, &handler)
  node = component(:range_slider, id:, lower:, upper:, **props)
  @application.register_handler(node.id, :change, handler) if handler
  node
end

#rebuild(node, &renderer) ⇒ Object



638
# File 'lib/zui/builder.rb', line 638

def rebuild(node, &renderer) = within_dynamic(node, &renderer)

#register_component(name, qml:, properties: [], events: [], property_map: {}, event_map: {}, container: false, auto_bind: true) ⇒ Object



58
59
60
61
62
63
# File 'lib/zui/builder.rb', line 58

def register_component(name, qml:, properties: [], events: [], property_map: {}, event_map: {}, container: false, auto_bind: true)
  unless @stack.empty? && @application.surfaces.empty?
    raise ArgumentError, "components must be registered before a surface"
  end
  @application.components.register(name, qml:, properties:, events:, property_map:, event_map:, container:, auto_bind:)
end

#reorderable_list(items = [], id: nil, **props) ⇒ Object



340
# File 'lib/zui/builder.rb', line 340

def reorderable_list(items = [], id: nil, **props) = component(:reorderable_list, id:, items: Array(items), **props)

#rich_text(markup, id: nil, **props) ⇒ Object



109
# File 'lib/zui/builder.rb', line 109

def rich_text(markup, id: nil, **props) = component(:rich_text, id:, text: markup.to_s, **props)

#round_button(label = "", id: nil, **props, &handler) ⇒ Object



429
430
431
# File 'lib/zui/builder.rb', line 429

def round_button(label = "", id: nil, **props, &handler)
  action_component(:round_button, :text, label, id:, props:, handler:)
end

#run_command(argv, **options) ⇒ Object



637
# File 'lib/zui/builder.rb', line 637

def run_command(argv, **options) = Command.run(argv, **options)

#screen_capture(id: nil, **props) ⇒ Object



596
# File 'lib/zui/builder.rb', line 596

def screen_capture(id: nil, **props) = component(:screen_capture, id:, **props)

#script_action(action = nil, id: nil, **props) ⇒ Object



565
# File 'lib/zui/builder.rb', line 565

def script_action(action = nil, id: nil, **props) = component(:script_action, id:, action:, **props)

#scroll_bar(target = nil, id: nil, **props) ⇒ Object



392
393
394
395
# File 'lib/zui/builder.rb', line 392

def scroll_bar(target = nil, id: nil, **props)
  props = props.merge(target: node_id(target)) unless target.nil?
  component(:scroll_bar, id:, **props)
end

#scroll_indicator(target = nil, id: nil, **props) ⇒ Object



396
397
398
399
# File 'lib/zui/builder.rb', line 396

def scroll_indicator(target = nil, id: nil, **props)
  props = props.merge(target: node_id(target)) unless target.nil?
  component(:scroll_indicator, id:, **props)
end

#search_field(value = "", id: nil, **props, &handler) ⇒ Object



467
468
469
470
471
# File 'lib/zui/builder.rb', line 467

def search_field(value = "", id: nil, **props, &handler)
  node = component(:search_field, id:, text: value.to_s, **props)
  @application.register_handler(node.id, :search, handler) if handler
  node
end

#section_header(value, id: nil, **props) ⇒ Object



410
# File 'lib/zui/builder.rb', line 410

def section_header(value, id: nil, **props) = component(:section_header, id:, text: value.to_s, **props)

#selectable_text(value, id: nil, **props) ⇒ Object



111
# File 'lib/zui/builder.rb', line 111

def selectable_text(value, id: nil, **props) = component(:selectable_text, id:, text: value.to_s, **props)

#selection_rectangle(target, id: nil, **props) ⇒ Object



391
# File 'lib/zui/builder.rb', line 391

def selection_rectangle(target, id: nil, **props) = component(:selection_rectangle, id:, target: node_id(target), **props)

#separator(id: nil, **props) ⇒ Object



408
# File 'lib/zui/builder.rb', line 408

def separator(id: nil, **props) = component(:separator, id:, **props)

#sequential_animation(animations = [], id: nil, **props) ⇒ Object



572
573
574
# File 'lib/zui/builder.rb', line 572

def sequential_animation(animations = [], id: nil, **props)
  component(:sequential_animation, id:, animations: normalize_animation_specs(animations), **props)
end

#settings(values = {}, id: nil, **props) ⇒ Object



604
# File 'lib/zui/builder.rb', line 604

def settings(values = {}, id: nil, **props) = component(:settings, id:, values:, **props)

#shader_effect(fragment_shader = nil, id: nil, shader: nil, **props, &block) ⇒ Object



376
377
378
379
380
381
# File 'lib/zui/builder.rb', line 376

def shader_effect(fragment_shader = nil, id: nil, shader: nil, **props, &block)
  effect_props = props.dup
  effect_props[:shader] = shader.to_s unless shader.nil?
  effect_props[:fragment_shader] = fragment_shader.to_s unless fragment_shader.nil?
  component(:shader_effect, id:, **effect_props, &block)
end

#shader_effect_source(id: nil, **props, &block) ⇒ Object



383
384
385
# File 'lib/zui/builder.rb', line 383

def shader_effect_source(id: nil, **props, &block)
  component(:shader_effect_source, id:, **props, &block)
end

#shape(path_data = "", id: nil, **props) ⇒ Object



356
357
358
# File 'lib/zui/builder.rb', line 356

def shape(path_data = "", id: nil, **props)
  component(:shape, id:, path: path_data.to_s, **props)
end

#skeleton(id: nil, **props) ⇒ Object



252
253
254
# File 'lib/zui/builder.rb', line 252

def skeleton(id: nil, **props)
  component(:skeleton, id:, **props)
end

#snackbar(message = "", id: nil, **props) ⇒ Object



231
232
233
# File 'lib/zui/builder.rb', line 231

def snackbar(message = "", id: nil, **props)
  component(:snackbar, id:, message: message.to_s, **props)
end

#sort_filter_proxy_model(items = [], id: nil, **props) ⇒ Object



602
# File 'lib/zui/builder.rb', line 602

def sort_filter_proxy_model(items = [], id: nil, **props) = component(:sort_filter_proxy_model, id:, items: Array(items), **props)

#sound_effect(source = "", id: nil, **props) ⇒ Object



583
# File 'lib/zui/builder.rb', line 583

def sound_effect(source = "", id: nil, **props) = component(:sound_effect, id:, source: source.to_s, **props)

#spacer(id: nil, **props) ⇒ Object



407
# File 'lib/zui/builder.rb', line 407

def spacer(id: nil, **props) = component(:spacer, id:, **props)

#stack_view(id: nil, **props, &block) ⇒ Object



161
162
163
# File 'lib/zui/builder.rb', line 161

def stack_view(id: nil, **props, &block)
  component(:stack_view, id:, **props, &block)
end

#standard_paths(location = :home, id: nil, **props) ⇒ Object



605
# File 'lib/zui/builder.rb', line 605

def standard_paths(location = :home, id: nil, **props) = component(:standard_paths, id:, location: location.to_s, **props)

#state(name = nil, initial = UNSET, target: nil, properties: nil, id: nil, **props) ⇒ Object

Raises:

  • (ArgumentError)


65
66
67
68
69
70
71
72
73
74
# File 'lib/zui/builder.rb', line 65

def state(name = nil, initial = UNSET, target: nil, properties: nil, id: nil, **props)
  unless target.nil?
    state_props = props.merge(target: node_id(target), name: name.to_s)
    state_props[:properties] = properties unless properties.nil?
    return component(:state, id:, **state_props)
  end
  return @application.state if name.nil?
  raise ArgumentError, "state requires an initial value" if initial.equal?(UNSET)
  @application.define_state(name, initial)
end

#swipe_delegate(text = "", id: nil, value: nil, **props, &handler) ⇒ Object



303
304
305
306
307
308
309
# File 'lib/zui/builder.rb', line 303

def swipe_delegate(text = "", id: nil, value: nil, **props, &handler)
  item_props = props.merge(text: text.to_s)
  item_props[:value] = value unless value.nil?
  node = component(:swipe_delegate, id:, **item_props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#swipe_view(id: nil, **props, &block) ⇒ Object



164
165
166
# File 'lib/zui/builder.rb', line 164

def swipe_view(id: nil, **props, &block)
  component(:swipe_view, id:, **props, &block)
end

#switch_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler) ⇒ Object



295
296
297
298
299
300
301
302
# File 'lib/zui/builder.rb', line 295

def switch_delegate(text = "", id: nil, value: nil, checked: UNSET, **props, &handler)
  item_props = props.merge(text: text.to_s)
  item_props[:value] = value unless value.nil?
  item_props[:checked] = checked unless checked.equal?(UNSET)
  node = component(:switch_delegate, id:, **item_props)
  @application.register_handler(node.id, :change, handler) if handler
  node
end

#tab_bar(items = [], id: nil, **props) ⇒ Object



152
153
154
# File 'lib/zui/builder.rb', line 152

def tab_bar(items = [], id: nil, **props)
  component(:tab_bar, id:, items: Array(items), **props)
end

#tab_button(label = "", id: nil, **props, &handler) ⇒ Object



155
156
157
# File 'lib/zui/builder.rb', line 155

def tab_button(label = "", id: nil, **props, &handler)
  action_component(:tab_button, :text, label, id:, props:, handler:)
end

#table_view(rows = [], id: nil, columns: [], **props, &handler) ⇒ Object



315
316
317
318
319
# File 'lib/zui/builder.rb', line 315

def table_view(rows = [], id: nil, columns: [], **props, &handler)
  node = component(:table_view, id:, rows: Array(rows), columns: Array(columns), **props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#table_view_delegate(text = "", id: nil, **props) ⇒ Object



336
# File 'lib/zui/builder.rb', line 336

def table_view_delegate(text = "", id: nil, **props) = component(:table_view_delegate, id:, text: text.to_s, **props)

#tabs(labels = [], id: nil, **props, &block) ⇒ Object



149
150
151
# File 'lib/zui/builder.rb', line 149

def tabs(labels = [], id: nil, **props, &block)
  component(:tabs, id:, labels: Array(labels), **props, &block)
end

#text(value = UNSET, id: nil, **props, &reader) ⇒ Object



98
99
100
101
102
# File 'lib/zui/builder.rb', line 98

def text(value = UNSET, id: nil, **props, &reader)
  node = component(:text, id:, **props)
  bind_or_set(node, "text", value, reader)
  node
end

#text_metrics(value, id: nil, **props) ⇒ Object



119
# File 'lib/zui/builder.rb', line 119

def text_metrics(value, id: nil, **props) = component(:text_metrics, id:, text: value.to_s, **props)

#timer(interval, id: nil, **props) ⇒ Object



576
# File 'lib/zui/builder.rb', line 576

def timer(interval, id: nil, **props) = component(:timer, id:, interval:, **props)

#toast(message = "", id: nil, **props) ⇒ Object



237
238
239
# File 'lib/zui/builder.rb', line 237

def toast(message = "", id: nil, **props)
  component(:toast, id:, message: message.to_s, **props)
end

#toggle(label = "", id: nil, checked: UNSET, **props, &handler) ⇒ Object



455
456
457
# File 'lib/zui/builder.rb', line 455

def toggle(label = "", id: nil, checked: UNSET, **props, &handler)
  input_component(:toggle, :checked, checked, id:, props: props.merge(label: label.to_s), handler:)
end

#toggle_switch(id: nil, checked: UNSET, **props, &handler) ⇒ Object



473
474
475
# File 'lib/zui/builder.rb', line 473

def toggle_switch(id: nil, checked: UNSET, **props, &handler)
  input_component(:toggle_switch, :checked, checked, id:, props:, handler:)
end

#tool_bar(id: nil, **props, &block) ⇒ Object



185
186
187
# File 'lib/zui/builder.rb', line 185

def tool_bar(id: nil, **props, &block)
  component(:tool_bar, id:, **props, &block)
end

#tool_button(label = "", id: nil, **props, &handler) ⇒ Object



433
434
435
# File 'lib/zui/builder.rb', line 433

def tool_button(label = "", id: nil, **props, &handler)
  action_component(:tool_button, :text, label, id:, props:, handler:)
end

#tool_separator(id: nil, **props) ⇒ Object



188
189
190
# File 'lib/zui/builder.rb', line 188

def tool_separator(id: nil, **props)
  component(:tool_separator, id:, **props)
end

#tooltip(value, id: nil, **props) ⇒ Object



114
# File 'lib/zui/builder.rb', line 114

def tooltip(value, id: nil, **props) = component(:tooltip, id:, text: value.to_s, **props)

#transaction(&block) ⇒ Object



633
# File 'lib/zui/builder.rb', line 633

def transaction(&block) = @application.state.transaction { instance_eval(&block) }

#tree_view(rows = [], id: nil, columns: [], children_field: :children, **props, &handler) ⇒ Object



321
322
323
324
325
326
# File 'lib/zui/builder.rb', line 321

def tree_view(rows = [], id: nil, columns: [], children_field: :children, **props, &handler)
  node = component(:tree_view, id:, rows: Array(rows), columns: Array(columns),
                              children_field: children_field.to_s, **props)
  @application.register_handler(node.id, :activate, handler) if handler
  node
end

#tree_view_delegate(text = "", id: nil, **props) ⇒ Object



337
# File 'lib/zui/builder.rb', line 337

def tree_view_delegate(text = "", id: nil, **props) = component(:tree_view_delegate, id:, text: text.to_s, **props)

#tumbler(items = [], id: nil, **props) ⇒ Object



350
# File 'lib/zui/builder.rb', line 350

def tumbler(items = [], id: nil, **props) = component(:tumbler, id:, items: Array(items), **props)

#vector_image(source, id: nil, **props) ⇒ Object



116
# File 'lib/zui/builder.rb', line 116

def vector_image(source, id: nil, **props) = component(:vector_image, id:, source: source.to_s, **props)

#vertical_header(sections = [], id: nil, **props) ⇒ Object



335
# File 'lib/zui/builder.rb', line 335

def vertical_header(sections = [], id: nil, **props) = component(:vertical_header, id:, sections: Array(sections), **props)

#vertical_header_delegate(text = "", id: nil, **props) ⇒ Object



339
# File 'lib/zui/builder.rb', line 339

def vertical_header_delegate(text = "", id: nil, **props) = component(:vertical_header_delegate, id:, text: text.to_s, **props)

#video(source, id: nil, **props) ⇒ Object



121
# File 'lib/zui/builder.rb', line 121

def video(source, id: nil, **props) = component(:video, id:, source: source.to_s, **props)

#video_output(source = nil, id: nil, **props) ⇒ Object



579
580
581
582
# File 'lib/zui/builder.rb', line 579

def video_output(source = nil, id: nil, **props)
  props = props.merge(source: node_id(source)) unless source.nil?
  component(:video_output, id:, **props)
end

#week_number_column(id: nil, **props) ⇒ Object



348
# File 'lib/zui/builder.rb', line 348

def week_number_column(id: nil, **props) = component(:week_number_column, id:, **props)

#widget_button(text = "", id: nil, **props, &handler) ⇒ Object



264
265
266
# File 'lib/zui/builder.rb', line 264

def widget_button(text = "", id: nil, **props, &handler)
  action_component(:widget_button, :text, text, id:, props:, handler:)
end

#window(title = "", id: nil, **props, &block) ⇒ Object



131
132
133
# File 'lib/zui/builder.rb', line 131

def window(title = "", id: nil, **props, &block)
  component(:window, id:, title: title.to_s, **props, &block)
end

#window_capture(id: nil, **props) ⇒ Object



597
# File 'lib/zui/builder.rb', line 597

def window_capture(id: nil, **props) = component(:window_capture, id:, **props)