Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spike for events, including mouse motion #292

Merged
merged 1 commit into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions examples/motion_events.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Shoes.app width: 600, height: 600 do
stack do
para "Events and Menus"
flow do
@btn1 = button "button 1", width: 75 do
@eb.append "button 1 clicked\n"
end
click do
@eb.append "flow click\n"
end
hover do
@eb.append "flow hover\n"
end
end
@eb = edit_box width: 500, height: 350
end
motion do |x, y, mods|
@eb.append "motion #{x},#{y} #{mods} "
end
end
12 changes: 12 additions & 0 deletions lib/scarpe/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,17 @@ def border(...)
current_slot.border(...)
end

def motion(&block)
subscription_item(shoes_api_name: "motion", &block)
end

def hover(&block)
subscription_item(shoes_api_name: "hover", &block)
end

def click(&block)
subscription_item(shoes_api_name: "click", &block)
end

alias_method :info, :puts
end
4 changes: 4 additions & 0 deletions lib/scarpe/display_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ def send_shoes_event(*args, event_name:, target: nil, **kwargs)
def bind_shoes_event(event_name:, target: nil, &handler)
DisplayService.subscribe_to_event(event_name, target, &handler)
end

def unsub_shoes_event(unsub_id)
DisplayService.unsub_from_events(unsub_id)
end
end

# These methods are an interface to DisplayService objects.
Expand Down
6 changes: 5 additions & 1 deletion lib/scarpe/document_root.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# frozen_string_literal: true

class Scarpe
class DocumentRoot < Scarpe::Slot
class DocumentRoot < Scarpe::Flow
def initialize
@height = "100%"
@width = @margin = @padding = nil
@options = {}

super

create_display_widget
Expand Down
6 changes: 5 additions & 1 deletion lib/scarpe/edit_box.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class EditBox < Scarpe::Widget
display_properties :text, :height, :width

def initialize(text = nil, height: nil, width: nil, &block)
@text = text.nil? ? block&.call : text || ""
@text = (text.nil? ? block&.call : text) || ""

super

Expand All @@ -20,5 +20,9 @@ def initialize(text = nil, height: nil, width: nil, &block)
def change(&block)
@callback = block
end

def append(new_text)
self.text = self.text + new_text
end
end
end
4 changes: 3 additions & 1 deletion lib/scarpe/flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ class Scarpe
class Flow < Scarpe::Slot
display_properties :width, :height, :margin, :padding

def initialize(width: nil, height: "100%", margin: nil, padding: nil, &block)
def initialize(width: nil, height: nil, margin: nil, padding: nil, **options, &block)
@options = options

super

# Create the display-side widget *before* instance_eval, which will add child widgets with their display widgets
Expand Down
1 change: 1 addition & 0 deletions lib/scarpe/slot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
class Scarpe::Slot < Scarpe::Widget
include Scarpe::Background
include Scarpe::Border
include Scarpe::Spacing
end
2 changes: 1 addition & 1 deletion lib/scarpe/spacing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
class Scarpe
module Spacing
def self.included(includer)
includer.display_properties :margin, :padding
includer.display_properties :margin, :padding, :margin_top, :margin_left, :margin_right, :margin_bottom, :options
end
end
end
8 changes: 3 additions & 5 deletions lib/scarpe/stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

class Scarpe
class Stack < Scarpe::Slot
include Scarpe::Spacing
# TODO: sort out various margin and padding properties, including putting stuff into spacing
display_properties :width, :height, :scroll

display_properties :width, :height, :margin, :padding, :scroll, :margin_top, :margin_left, :margin_right, :margin_bottom, :options

def initialize(width: nil, height: "100%", margin: nil, padding: nil, scroll: false, margin_top: nil, margin_bottom: nil, margin_left: nil,
def initialize(width: nil, height: nil, margin: nil, padding: nil, scroll: false, margin_top: nil, margin_bottom: nil, margin_left: nil,
margin_right: nil, **options, &block)

# TODO: what are these options? Are they guaranteed serializable?
@options = options

super
Expand Down
60 changes: 60 additions & 0 deletions lib/scarpe/subscription_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

# Certain Shoes calls like motion and keydown are basically an
# event subscription, with no other visible presence. However,
# they have a place in the widget tree and can be deleted.
#
# Depending on the display library they may not have any
# direct visual (or similar) presence there either.
#
# Inheriting from Widget gives these a parent slot and a
# linkable_id automatically.
class SubscriptionItem < Scarpe::Widget
display_property :shoes_api_name

def initialize(shoes_api_name:, &block)
super

@callback = block

case shoes_api_name
when "hover"
# Hover passes the Shoes widget as the block param
@unsub_id = bind_self_event("hover") do
@callback&.call(self)
end
when "motion"
# Shoes sends back x, y, mods as the args.
# Shoes3 uses the strings "control" "shift" and
# "control_shift" as the mods arg.
@unsub_id = bind_self_event("motion") do |x, y, ctrl_key, shift_key, **_kwargs|
mods = [ctrl_key ? "control" : nil, shift_key ? "shift" : nil].compact.join("_")
@callback&.call(x, y, mods)
end
when "click"
# Click has block params button, left, top
# button is the button number, left and top are coords
@unsub_id = bind_self_event("click") do |button, x, y, **_kwargs|
@callback&.call(button, x, y)
end
else
raise "Unknown Shoes API call #{shoes_api_name.inspect} passed to SubscriptionItem!"
end

@unsub_id = bind_self_event(shoes_api_name) do |*args|
@callback&.call(*args)
end

# This won't create a visible display widget, but will turn into
# an invisible widget and a stream of events.
create_display_widget
end

def destroy
# TODO: we need a better way to do this automatically. See https://github.com/scarpe-team/scarpe/issues/291
unsub_shoes_event(@unsub_id) if @unsub_id
@unsub_id = nil

super
end
end
3 changes: 2 additions & 1 deletion lib/scarpe/widgets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
require_relative "fill"

require_relative "slot"
require_relative "document_root"
require_relative "para"
require_relative "stack"
require_relative "flow"
require_relative "document_root"
require_relative "download"
require_relative "subscription_item"
require_relative "button"
require_relative "image"
require_relative "edit_box"
Expand Down
2 changes: 2 additions & 0 deletions lib/scarpe/wv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@

require_relative "wv/app"
require_relative "wv/para"
require_relative "wv/slot"
require_relative "wv/stack"
require_relative "wv/flow"
require_relative "wv/document_root"
require_relative "wv/subscription_item"
require_relative "wv/button"
require_relative "wv/image"
require_relative "wv/edit_box"
Expand Down
15 changes: 2 additions & 13 deletions lib/scarpe/wv/flow.rb
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
# frozen_string_literal: true

class Scarpe
class WebviewFlow < Scarpe::WebviewWidget
include Scarpe::WebviewBackground
include Scarpe::WebviewBorder

class WebviewFlow < Scarpe::WebviewSlot
def initialize(properties)
super
end

def element(&block)
HTML.render do |h|
h.div(id: html_id, style:, &block)
end
end

private
protected

def style
styles = super

styles[:display] = "flex"
styles["flex-direction"] = "row"
styles["flex-wrap"] = "wrap"
styles[:width] = Dimensions.length(@width) if @width
styles[:height] = Dimensions.length(@height) if @height

styles
end
Expand Down
1 change: 1 addition & 0 deletions lib/scarpe/wv/shape.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require_relative "shape_helper"

class Scarpe
# Should inherit from Slot?
class WebviewShape < Scarpe::WebviewWidget
include ShapeHelper

Expand Down
81 changes: 81 additions & 0 deletions lib/scarpe/wv/slot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

class Scarpe
class WebviewSlot < Scarpe::WebviewWidget
include Scarpe::WebviewBackground
include Scarpe::WebviewBorder
include Scarpe::WebviewSpacing

def initialize(properties)
@event_callbacks = {}

super
end

def element(&block)
HTML.render do |h|
h.div(attributes.merge(id: html_id, style: style), &block)
end
end

def set_event_callback(obj, event_name, js_code)
event_name = event_name.to_s
@event_callbacks[event_name] ||= {}
if @event_callbacks[event_name][obj]
raise "Can't have two callbacks on the same event, from the same object, on the same parent!"
end

@event_callbacks[event_name][obj] = js_code

update_dom_event(event_name)
end

def remove_event_callback(obj, event_name)
event_name = event_name.to_s
@event_callbacks[event_name] ||= {}
@event_callbacks[event_name].delete(obj)

update_dom_event(event_name)
end

def remove_event_callbacks(obj)
changed = []

@event_callbacks.each do |event_name, items|
changed << event_name if items.delete(obj)
end

changed.each { |event_name| update_dom_event(event_name) }
end

protected

def update_dom_event(event_name)
html_element.set_attribute(event_name, @event_callbacks[event_name].values.join(";"))
end

def attributes
attr = {}

@event_callbacks.each do |event_name, handlers|
attr[event_name] = handlers.values.join(";")
end

attr
end

def style
styles = super

styles["margin-top"] = @margin_top if @margin_top
styles["margin-bottom"] = @margin_bottom if @margin_bottom
styles["margin-left"] = @margin_left if @margin_left
styles["margin-right"] = @margin_right if @margin_right

styles[:width] = Dimensions.length(@width) if @width
styles[:height] = Dimensions.length(@height) if @height

styles
end
end
end
2 changes: 1 addition & 1 deletion lib/scarpe/wv/spacing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module WebviewSpacing
SPACING_DIRECTIONS = [:left, :right, :top, :bottom]

def style
styles = (super if defined?(super)) || {}
styles = defined?(super) ? super : {}

extract_spacing_styles_for(:margin, styles, @margin)
extract_spacing_styles_for(:padding, styles, @padding)
Expand Down
25 changes: 2 additions & 23 deletions lib/scarpe/wv/stack.rb
Original file line number Diff line number Diff line change
@@ -1,39 +1,18 @@
# frozen_string_literal: true

class Scarpe
class WebviewStack < Scarpe::WebviewWidget
include Scarpe::WebviewBackground
include Scarpe::WebviewBorder
include Scarpe::WebviewSpacing

def initialize(properties)
super
end

def element(&block)
HTML.render do |h|
h.div(id: html_id, style: style, &block)
end
end

class WebviewStack < Scarpe::WebviewSlot
def get_style
style
end

private
protected

def style
styles = super

styles["margin-top"] = @margin_top if @margin_top
styles["margin-bottom"] = @margin_bottom if @margin_bottom
styles["margin-left"] = @margin_left if @margin_left
styles["margin-right"] = @margin_right if @margin_right

styles[:display] = "flex"
styles["flex-direction"] = "column"
styles[:width] = Dimensions.length(@width) if @width
styles[:height] = Dimensions.length(@height) if @height
styles["overflow"] = "auto" if @scroll

styles
Expand Down
Loading