glimmer-dsl-opal 0.26.3 → 0.28.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ module Glimmer
2
+ module SWT
3
+ # emulating org.eclipse.swt.graphics.Image
4
+ class ImageProxy
5
+ class << self
6
+ def create(*args, &content)
7
+ if args.size == 1 && args.first.is_a?(ImageProxy)
8
+ args.first
9
+ else
10
+ new(*args, &content)
11
+ end
12
+ end
13
+ end
14
+
15
+ attr_reader :file_path, :width, :height
16
+
17
+ def initialize(*args)
18
+ options = args.last.is_a?(Hash) ? args.last : {}
19
+ # TODO support a parent as a first argument before the file path
20
+ @file_path = args.first
21
+ @width = options[:width]
22
+ @height = options[:height]
23
+ end
24
+
25
+ # TODO implement scale_to
26
+ end
27
+ # TODO alias as org.eclipse.swt.graphics.Image
28
+ end
29
+ end
@@ -1,5 +1,7 @@
1
1
  module Glimmer
2
2
  module SWT
3
+ # emulating org.eclipse.swt.graphics.Point
3
4
  Point = Struct.new(:x, :y)
5
+ # TODO alias as org.eclipse.swt.graphics.Point
4
6
  end
5
7
  end
@@ -0,0 +1,7 @@
1
+ module Glimmer
2
+ module SWT
3
+ # emulating org.eclipse.swt.graphics.Rectangle
4
+ Rectangle = Struct.new(:x, :y, :width, :height)
5
+ # TODO alias as org.eclipse.swt.graphics.Rectangle
6
+ end
7
+ end
@@ -3,7 +3,26 @@ require 'glimmer/swt/widget_proxy'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class TextProxy < WidgetProxy
6
- attr_reader :text
6
+ attr_reader :text, :border, :left, :center, :right, :read_only, :wrap, :multi
7
+ alias border? border
8
+ alias left? left
9
+ alias center? center
10
+ alias right? right
11
+ alias read_only? read_only
12
+ alias wrap? wrap
13
+ alias multi? multi
14
+
15
+ def initialize(parent, args, block)
16
+ args << :border if args.empty?
17
+ @border = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:border] }
18
+ @left = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:left] }
19
+ @center = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:center] }
20
+ @right = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:right] }
21
+ @read_only = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:read_only] }
22
+ @wrap = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:wrap] }
23
+ @multi = !!args.detect { |arg| SWTProxy[arg] == SWTProxy[:multi] }
24
+ super(parent, args, block)
25
+ end
7
26
 
8
27
  def text=(value)
9
28
  @text = value
@@ -11,43 +30,86 @@ module Glimmer
11
30
  end
12
31
 
13
32
  def element
14
- 'input'
33
+ @wrap || @multi ? 'textarea' : 'input'
15
34
  end
16
35
 
17
36
  def observation_request_to_event_mapping
37
+ myself = self
18
38
  {
19
- 'on_modify_text' => {
20
- event: 'keyup',
21
- event_handler: -> (event_listener) {
22
- -> (event) {
23
- # TODO consider unifying this event handler with on_key_pressed by relying on its result instead of hooking another keyup event
24
- # TODO add all attributes for on_modify_text modify event
25
- if @last_key_pressed_event.nil? || @last_key_pressed_event.doit
39
+ 'on_verify_text' => [
40
+ {
41
+ event: 'beforeinput',
42
+ event_handler: -> (event_listener) {
43
+ -> (event) {
44
+ event.define_singleton_method(:widget) {myself}
45
+ event.define_singleton_method(:text) {`#{event.to_n}.originalEvent.data` || ''}
46
+ selection_start = `#{event.target}[0].selectionStart`
47
+ selection_end = `#{event.target}[0].selectionEnd`
48
+ if `#{event.to_n}.originalEvent.inputType` == 'deleteContentBackward' && selection_start == selection_end
49
+ selection_start -= 1
50
+ selection_start = 0 if selection_start < 0
51
+ end
52
+ event.define_singleton_method(:start) do
53
+ selection_start
54
+ end
55
+ event.define_singleton_method(:end) {selection_end}
56
+ doit = true
57
+ event.define_singleton_method(:doit=) do |value|
58
+ doit = value
59
+ end
60
+ event.define_singleton_method(:doit) { doit }
61
+ event_listener.call(event)
62
+
63
+ if !doit
64
+ `#{event.to_n}.originalEvent.returnValue = false`
65
+ end
66
+
67
+ doit
68
+ }
69
+ }
70
+ },
71
+ {
72
+ event: 'input',
73
+ event_handler: -> (event_listener) {
74
+ -> (event) {
75
+ event.define_singleton_method(:widget) {myself}
76
+ @text = event.target.value
77
+ }
78
+ }
79
+ }
80
+ ],
81
+ 'on_modify_text' => [
82
+ {
83
+ event: 'input',
84
+ event_handler: -> (event_listener) {
85
+ -> (event) {
86
+ # TODO add all attributes for on_modify_text modify event
87
+ event.define_singleton_method(:widget) {myself}
26
88
  @text = event.target.value
27
89
  event_listener.call(event)
28
- else
29
- # TODO Fix doit false, it's not stopping input
30
- event.prevent
31
- event.prevent_default
32
- event.stop_propagation
33
- event.stop_immediate_propagation
34
- end
90
+ }
35
91
  }
36
92
  }
37
- },
93
+ ],
38
94
  }
39
95
  end
40
96
 
41
97
  def dom
42
98
  text_text = @text
43
99
  text_id = id
44
- text_style = css
100
+ text_style = 'min-width: 27px; '
101
+ text_style += 'border: none; ' if !@border
102
+ text_style += 'text-align: left; ' if @left
103
+ text_style += 'text-align: center; ' if @center
104
+ text_style += 'text-align: right; ' if @right
45
105
  text_class = name
46
- options = {type: 'text', id: text_id, style: text_style, class: text_class, value: text_text, style: 'min-width: 27px;'}
106
+ options = {type: 'text', id: text_id, style: text_style, class: text_class, value: text_text}
47
107
  options = options.merge('disabled': 'disabled') unless @enabled
108
+ options = options.merge('readonly': 'readonly') if @read_only
109
+ options = options.merge('contenteditable': 'true')
48
110
  options = options.merge(type: 'password') if has_style?(:password)
49
111
  @dom ||= html {
50
- input(options)
112
+ send(element, options)
51
113
  }.to_s
52
114
  end
53
115
  end
@@ -30,7 +30,7 @@ module Glimmer
30
30
  class WidgetProxy
31
31
  include Glimmer
32
32
  include PropertyOwner
33
-
33
+
34
34
  Event = Struct.new(:widget, keyword_init: true)
35
35
 
36
36
  JS_KEY_CODE_TO_SWT_KEY_CODE_MAP = {
@@ -158,7 +158,7 @@ module Glimmer
158
158
  @block = block
159
159
  # TODO consider changing children to an array (why is it a Set if order matters?)
160
160
  @children = Set.new # TODO consider moving to composite
161
- @enabled = true
161
+ @enabled = true if @enabled.nil?
162
162
  DEFAULT_INITIALIZERS[self.class.underscored_widget_name(self).to_s.to_sym]&.call(self)
163
163
  @parent.post_initialize_child(self) # TODO rename to post_initialize_child to be closer to glimmer-dsl-swt terminology
164
164
  end
@@ -331,9 +331,10 @@ module Glimmer
331
331
  brand_new = @dom.nil? || old_element.empty? || brand_new
332
332
  build_dom(layout: !custom_parent_dom_element) # TODO handle custom parent layout by passing parent instead of parent dom element
333
333
  if brand_new
334
- the_parent_dom_element.append(@dom) # TODO make a method attach to allow subclasses to override if needed
334
+ # TODO make a method attach to allow subclasses to override if needed
335
+ attach(the_parent_dom_element)
335
336
  else
336
- old_element.replace_with(@dom)
337
+ reattach(old_element)
337
338
  end
338
339
  observation_requests&.each do |keyword, event_listener_set|
339
340
  event_listener_set.each do |event_listener|
@@ -347,6 +348,14 @@ module Glimmer
347
348
  content_on_render_blocks.each { |content_block| content(&content_block) } unless skip_content_on_render_blocks?
348
349
  end
349
350
  alias redraw render
351
+
352
+ def attach(the_parent_dom_element)
353
+ the_parent_dom_element.append(@dom)
354
+ end
355
+
356
+ def reattach(old_element)
357
+ old_element.replace_with(@dom)
358
+ end
350
359
 
351
360
  def content_on_render_blocks
352
361
  @content_on_render_blocks ||= []
@@ -367,7 +376,7 @@ module Glimmer
367
376
  def build_dom(layout: true)
368
377
  # TODO consider passing parent element instead and having table item include a table cell widget only for opal
369
378
  @dom = nil
370
- @dom = dom
379
+ @dom = dom # TODO unify how to build dom for most widgets based on element, id, and name (class)
371
380
  @dom = @parent.get_layout.dom(@dom) if @parent.respond_to?(:layout) && @parent.get_layout
372
381
  @dom
373
382
  end
@@ -616,6 +625,7 @@ module Glimmer
616
625
  JS_KEY_CODE_TO_SWT_KEY_CODE_MAP[event.which] || event.which
617
626
  }
618
627
  event.define_singleton_method(:key_code, &event.method(:keyCode))
628
+ event.define_singleton_method(:widget) {myself}
619
629
  event.define_singleton_method(:character) {event.which.chr}
620
630
  event.define_singleton_method(:stateMask) do
621
631
  state_mask = 0
@@ -658,6 +668,7 @@ module Glimmer
658
668
  JS_KEY_CODE_TO_SWT_KEY_CODE_MAP[event.which] || event.which
659
669
  }
660
670
  event.define_singleton_method(:key_code, &event.method(:keyCode))
671
+ event.define_singleton_method(:widget) {myself}
661
672
  event.define_singleton_method(:character) {event.which.chr}
662
673
  event.define_singleton_method(:stateMask) do
663
674
  state_mask = 0
@@ -1141,6 +1152,7 @@ require 'glimmer/swt/combo_proxy'
1141
1152
  require 'glimmer/swt/c_combo_proxy'
1142
1153
  require 'glimmer/swt/checkbox_proxy'
1143
1154
  require 'glimmer/swt/composite_proxy'
1155
+ require 'glimmer/swt/canvas_proxy'
1144
1156
  require 'glimmer/swt/date_time_proxy'
1145
1157
  require 'glimmer/swt/group_proxy'
1146
1158
  require 'glimmer/swt/label_proxy'
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2007-2021 Andy Maleh
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
@@ -25,11 +25,7 @@ require_relative 'tetris/view/playfield'
25
25
  require_relative 'tetris/view/score_lane'
26
26
  require_relative 'tetris/view/high_score_dialog'
27
27
  require_relative 'tetris/view/tetris_menu_bar'
28
- class Event
29
- def location
30
- `#@native.location`
31
- end
32
- end
28
+
33
29
  class Tetris
34
30
  include Glimmer::UI::CustomShell
35
31
 
@@ -147,7 +143,7 @@ class Tetris
147
143
  def show_about_dialog
148
144
  message_box {
149
145
  text 'Glimmer Tetris'
150
- message "Glimmer Tetris\n\nGlimmer DSL for SWT Sample\n\nUse arrow keys for movement\nand right/left alt/shift keys for rotation\nAlternatively:\nLeft is A\nRight is D\nDown is S\nUp is W\nRotate Left is Q\nRotate Right is E\n\n for Left, Down, Right, Up\n\nCopyright (c) 2007-2021 Andy Maleh"
146
+ message "Glimmer Tetris\n\nGlimmer DSL for SWT Sample\n\nUse arrow keys for movement\nand right/left alt/shift keys for rotation\nAlternatively:\nLeft is A\nRight is D\nDown is S\nUp is W\nRotate Left is Q\nRotate Right is E\n\nCopyright (c) 2007-2021 Andy Maleh"
151
147
  }.open
152
148
  end
153
149
  end
@@ -0,0 +1,91 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class HelloCanvas
23
+ include Glimmer::UI::CustomShell
24
+
25
+ before_body do
26
+ @image_object = image(File.expand_path('./images/scaffold_app.png', __dir__), width: 50)
27
+ end
28
+
29
+ body {
30
+ shell {
31
+ text 'Hello, Canvas!'
32
+ minimum_size 320, 400
33
+
34
+ canvas {
35
+ background :yellow
36
+
37
+ rectangle(0, 0, 220, 400) {
38
+ background rgb(255, 0, 0)
39
+ }
40
+ rectangle(50, 20, 300, 150, 30, 50) {
41
+ background :magenta
42
+ }
43
+ rectangle(50, 20, 300, 150, 30, 50) {
44
+ foreground :yellow
45
+ }
46
+ rectangle(205, 50, 86, 97) {
47
+ foreground :yellow
48
+ }
49
+ rectangle(67, 75, 128, 38) {
50
+ background :yellow
51
+ }
52
+ rectangle(150, 200, 100, 70) {
53
+ background :dark_magenta
54
+ }
55
+ rectangle(50, 200, 30, 70) {
56
+ background :magenta
57
+ }
58
+ oval(110, 310, 100, 100) {
59
+ background :yellow
60
+ }
61
+ arc(210, 210, 100, 100, 30, -77) {
62
+ background :red
63
+ }
64
+ text('Picasso', 67, 103) {
65
+ foreground :dark_magenta
66
+ font name: 'Courier', height: 30
67
+ }
68
+ image(@image_object, 205, 55)
69
+ polygon(250, 210, 260, 170, 270, 210, 290, 230) {
70
+ background :dark_yellow
71
+ }
72
+ polyline(250, 110, 260, 70, 270, 110, 290, 130, 250, 110) {
73
+ foreground :black
74
+ }
75
+ 3.times do |n|
76
+ line(250, 120 + n*10, 270 + n*10, 80 + n*10) {
77
+ foreground :yellow
78
+ }
79
+ end
80
+ 10.times do |n|
81
+ point(220 + n*5, 100 + n*5) {
82
+ foreground :yellow
83
+ }
84
+ end
85
+ }
86
+ }
87
+ }
88
+ end
89
+
90
+ HelloCanvas.launch
91
+
@@ -0,0 +1,149 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ class HelloText
23
+ include Glimmer::UI::CustomShell
24
+
25
+ attr_accessor :default, :no_border, :center, :left, :right, :password, :telephone, :read_only, :wrap, :multi
26
+
27
+ before_body do
28
+ self.default = 'default is :border style'
29
+ self.no_border = 'no border'
30
+ self.center = 'centered'
31
+ self.left = 'left-aligned'
32
+ self.right = 'right-aligned'
33
+ self.password = 'password'
34
+ self.telephone = '555-555-5555'
35
+ self.read_only = 'Telephone area code is 555'
36
+ self.wrap = 'wraps if text content is too long like this example'
37
+ self.multi = "multi-line enables hitting enter,\nbut works like wrap on the web"
38
+ end
39
+
40
+ body {
41
+ shell {
42
+ grid_layout 2, false
43
+
44
+ text 'Hello, Text!'
45
+ minimum_size 350, 100
46
+
47
+ label {
48
+ text 'text'
49
+ }
50
+ text { # includes :border style by default
51
+ layout_data :fill, :center, true, false
52
+ text <=> [self, :default]
53
+ }
54
+
55
+ label {
56
+ text 'text(:none)'
57
+ }
58
+ text(:none) { # no border
59
+ layout_data :fill, :center, true, false
60
+ text <=> [self, :no_border]
61
+ }
62
+
63
+ label {
64
+ text 'text(:center, :border)'
65
+ }
66
+ text(:center, :border) {
67
+ layout_data :fill, :center, true, false
68
+ text <=> [self, :center]
69
+ }
70
+
71
+ label {
72
+ text 'text(:left, :border)'
73
+ }
74
+ text(:left, :border) {
75
+ layout_data :fill, :center, true, false
76
+ text <=> [self, :left]
77
+ }
78
+
79
+ label {
80
+ text 'text(:right, :border)'
81
+ }
82
+ text(:right, :border) {
83
+ layout_data :fill, :center, true, false
84
+ text <=> [self, :right]
85
+ }
86
+
87
+ label {
88
+ text 'text(:password, :border)'
89
+ }
90
+ text(:password, :border) {
91
+ layout_data :fill, :center, true, false
92
+ text <=> [self, :password]
93
+ }
94
+
95
+ label {
96
+ text 'text(:read_only, :border)'
97
+ }
98
+ text(:read_only, :border) {
99
+ layout_data :fill, :center, true, false
100
+ text <= [self, :read_only]
101
+ }
102
+
103
+ label {
104
+ text 'text with event handlers'
105
+ }
106
+ text {
107
+ layout_data :fill, :center, true, false
108
+ text <=> [self, :telephone]
109
+
110
+ # this event kicks in just after the user typed and before modifying the text attribute value
111
+ on_verify_text do |verify_event|
112
+ new_text = verify_event.widget.text.clone
113
+ # new_text[verify_event.start...verify_event.end] = verify_event.text # Opal does not allow string mutation like JRuby in Glimmer DSL for SWT
114
+ new_text = "#{new_text[0...verify_event.start]}#{verify_event.text}#{new_text[verify_event.end..-1]}"
115
+ verify_event.doit = telephone?(new_text)
116
+ end
117
+
118
+ # this event kicks in just after the text widget is verified and modified
119
+ on_modify_text do |modify_event|
120
+ self.read_only = "Telephone area code is #{modify_event.widget.text.gsub(/[^0-9]/, '')[0...3]}"
121
+ end
122
+ }
123
+
124
+ label {
125
+ text 'text(:wrap, :border)'
126
+ }
127
+ text(:wrap, :border) {
128
+ layout_data(:fill, :center, true, false) {
129
+ width_hint 100
130
+ }
131
+ text <=> [self, :wrap]
132
+ }
133
+
134
+ label {
135
+ text 'text(:multi, :border)'
136
+ }
137
+ text(:multi, :border) {
138
+ layout_data :fill, :center, true, false
139
+ text <=> [self, :multi]
140
+ }
141
+ }
142
+ }
143
+
144
+ def telephone?(text)
145
+ !!text.match(/^\d{0,3}[-.\/]?\d{0,3}[-.\/]?\d{0,4}$/)
146
+ end
147
+ end
148
+
149
+ HelloText.launch