glimmer-dsl-swt 4.18.3.5 → 4.18.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.18.3.5
1
+ 4.18.4.0
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-swt 4.18.3.5 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.4.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.3.5"
9
+ s.version = "4.18.4.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-02-01"
14
+ s.date = "2021-02-02"
15
15
  s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.executables = ["glimmer".freeze, "girb".freeze]
@@ -136,6 +136,7 @@ Gem::Specification.new do |s|
136
136
  "samples/elaborate/contact_manager/contact_repository.rb",
137
137
  "samples/elaborate/login.rb",
138
138
  "samples/elaborate/meta_sample.rb",
139
+ "samples/elaborate/meta_sample/meta_sample_logo.png",
139
140
  "samples/elaborate/tetris.rb",
140
141
  "samples/elaborate/tetris/model/block.rb",
141
142
  "samples/elaborate/tetris/model/game.rb",
@@ -183,6 +184,7 @@ Gem::Specification.new do |s|
183
184
  "samples/hello/hello_styled_text.rb",
184
185
  "samples/hello/hello_tab.rb",
185
186
  "samples/hello/hello_table.rb",
187
+ "samples/hello/hello_table/baseball_park.png",
186
188
  "samples/hello/hello_world.rb",
187
189
  "vendor/swt/linux/swt.jar",
188
190
  "vendor/swt/mac/swt.jar",
@@ -37,7 +37,7 @@ module Glimmer
37
37
  @property = property
38
38
  @translator = translator || proc {|value| value} #TODO check on this it doesn't seem used
39
39
 
40
- if @widget.respond_to?(:dispose)
40
+ if @widget.respond_to?(:on_widget_disposed)
41
41
  @widget.on_widget_disposed do |dispose_event|
42
42
  unregister_all_observables
43
43
  end
@@ -30,56 +30,23 @@ module Glimmer
30
30
  # TODO support switcher of language that automatically updates the lexer
31
31
  # TODO support method for redrawing the syntax highlighting
32
32
  option :theme, default: 'glimmer'
33
- # option :lines, default: false
33
+ option :lines, default: false
34
34
 
35
- # attr_accessor :code_text_widget_text, :code_text_widget_top_pixel
36
- # attr_reader :styled_text_proxy
35
+ alias lines? lines
36
+ attr_accessor :styled_text_proxy_text, :styled_text_proxy_top_pixel
37
+ attr_reader :styled_text_proxy, :lines_width
37
38
 
38
-
39
-
40
- # def text=(value)
41
- # if lines
42
- # @styled_text_proxy&.swt_widget&.text = value
43
- # else
44
- # super
45
- # end
46
- # end
47
-
48
- # def text(*args)
49
- # if lines
50
- # @styled_text_proxy&.swt_widget&.text
51
- # else
52
- # super
53
- # end
54
- # end
55
-
56
- # def lines_width
57
- # if lines == true
58
- # 4
59
- # elsif lines.is_a?(Hash)
60
- # lines[:width]
61
- # end
62
- # end
63
-
64
- def syntax_highlighting(text)
65
- return [] if text.to_s.strip.empty?
66
- @syntax_highlighting ||= {}
67
- unless @syntax_highlighting.keys.include?(text)
68
- lex = lexer.lex(text).to_a
69
- text_size = 0
70
- @syntax_highlighting[text] = lex.map do |pair|
71
- {token_type: pair.first, token_text: pair.last}
72
- end.each do |hash|
73
- hash[:token_index] = text_size
74
- text_size += hash[:token_text].size
75
- end
76
- end
77
- @syntax_highlighting[text]
39
+ def text=(value)
40
+ @styled_text_proxy&.swt_widget&.text = value
78
41
  end
79
42
 
80
- def lexer
81
- # TODO Try to use Rouge::Lexer.find_fancy('guess', code) in the future to guess the language or otherwise detect it from file extension
82
- @lexer ||= Rouge::Lexer.find_fancy(language)
43
+ def text(*args, dsl: false, &block)
44
+ # If dsl: true is passed, operate using Glimmer DSL (which is the default that happens through super method_missing)
45
+ if dsl
46
+ super(*args, &block)
47
+ else
48
+ @styled_text_proxy&.swt_widget&.text
49
+ end
83
50
  end
84
51
 
85
52
  before_body {
@@ -87,60 +54,65 @@ module Glimmer
87
54
  require 'ext/rouge/themes/glimmer'
88
55
  @swt_style = swt_style == 0 ? [:border, :multi, :v_scroll, :h_scroll] : swt_style
89
56
  @font_name = display.get_font_list(nil, true).map(&:name).include?('Consolas') ? 'Consolas' : 'Courier'
57
+ if lines == true
58
+ @lines_width = 4
59
+ elsif lines.is_a?(Hash)
60
+ @lines_width = lines[:width]
61
+ end
90
62
  }
91
63
 
92
64
  body {
93
65
  # TODO enable this once fully implemented
94
- # if lines
95
- # composite {
96
- # grid_layout(2, false)
97
- # layout_data :fill, :fill, true, true
98
- # @line_numbers_text = styled_text(:multi, :border) {
99
- # layout_data(:right, :fill, false, true)
100
- # text ' 1'
101
- # line_count = code_text_widget_text.to_s.split("\n").count
102
- # line_count = 1 if line_count == 0
103
- # lines_text_size = [line_count.to_s.size, 4].max
104
- # text line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
105
- # text bind(self, :code_text_widget_text, read_only: true) { |text_value|
106
- # line_count = text_value.to_s.split("\n").count
107
- # line_count = 1 if line_count == 0
108
- # lines_text_size = [line_count.to_s.size, 4].max
109
- # line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n")
110
- # }
111
- # top_pixel bind(self, :code_text_widget_top_pixel, read_only: true)
112
- # font name: @font_name, height: OS.mac? ? 15 : 12
113
- # background color(:widget_background)
114
- # foreground :dark_blue
115
- # top_margin 5
116
- # right_margin 5
117
- # bottom_margin 5
118
- # left_margin 5
119
- # editable false
120
- # caret nil
121
- # on_focus_gained {
122
- # @styled_text_proxy&.swt_widget.setFocus
123
- # }
124
- # on_key_pressed {
125
- # @styled_text_proxy&.swt_widget.setFocus
126
- # }
127
- # on_mouse_up {
128
- # @styled_text_proxy&.swt_widget.setFocus
129
- # }
130
- # }
131
- #
132
- # code_text_widget
133
- # }
134
- # else
66
+ if lines
67
+ composite {
68
+ grid_layout(2, false)
69
+
70
+ @line_numbers_text = styled_text(:multi, :border) {
71
+ layout_data(:right, :fill, false, true)
72
+ text ' '*lines_width.to_i
73
+ text(bind(self, :styled_text_proxy_text, read_only: true) { |text_value|
74
+ line_count = text_value.to_s.split("\n").count
75
+ line_count = 1 if line_count == 0
76
+ lines_text_size = [line_count.to_s.size, @lines_width].max
77
+ if lines_text_size > @lines_width
78
+ async_exec { swt_widget.layout }
79
+ @lines_width = lines_text_size
80
+ end
81
+ line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n") + "\n"
82
+ }, dsl: true)
83
+ top_pixel bind(self, :styled_text_proxy_top_pixel, read_only: true)
84
+ font name: @font_name, height: OS.mac? ? 15 : 12
85
+ background color(:widget_background)
86
+ foreground :dark_blue
87
+ top_margin 5
88
+ right_margin 5
89
+ bottom_margin 5
90
+ left_margin 5
91
+ editable false
92
+ caret nil
93
+ on_focus_gained {
94
+ @styled_text_proxy&.swt_widget.setFocus
95
+ }
96
+ on_key_pressed {
97
+ @styled_text_proxy&.swt_widget.setFocus
98
+ }
99
+ on_mouse_up {
100
+ @styled_text_proxy&.swt_widget.setFocus
101
+ }
102
+ }
103
+
104
+ code_text_widget
105
+ }
106
+ else
135
107
  code_text_widget
136
- # end
108
+ end
137
109
  }
138
110
 
139
111
  def code_text_widget
140
112
  @styled_text_proxy = styled_text(swt_style) {
141
- # layout_data :fill, :fill, true, true if lines
142
- # text bind(self, :code_text_widget_text) if lines
143
- # top_pixel bind(self, :code_text_widget_top_pixel) if lines
113
+ layout_data :fill, :fill, true, true if lines
114
+ text(bind(self, :styled_text_proxy_text), dsl: true) if lines
115
+ top_pixel bind(self, :styled_text_proxy_top_pixel) if lines
144
116
  font name: @font_name, height: 15
145
117
  foreground rgb(75, 75, 75)
146
118
  left_margin 5
@@ -148,6 +120,20 @@ module Glimmer
148
120
  right_margin 5
149
121
  bottom_margin 5
150
122
 
123
+ if lines
124
+ on_key_pressed { |event|
125
+ character = event.keyCode.chr rescue nil
126
+ case [event.stateMask, character]
127
+ when [(OS.mac? ? swt(:command) : swt(:ctrl)), 'a']
128
+ @styled_text_proxy.swt_widget.selectAll
129
+ when [(swt(:ctrl) unless OS.windows?), 'a']
130
+ jump_to_beginning_of_line
131
+ when [(swt(:ctrl) unless OS.windows?), 'e']
132
+ jump_to_end_of_line
133
+ end
134
+ }
135
+ end
136
+
151
137
  on_modify_text { |event|
152
138
  # clear unnecessary syntax highlighting cache on text updates, and do it async to avoid affecting performance
153
139
  new_text = event.data
@@ -188,6 +174,29 @@ module Glimmer
188
174
  }
189
175
  end
190
176
 
177
+ def syntax_highlighting(text)
178
+ return [] if text.to_s.strip.empty?
179
+ @syntax_highlighting ||= {}
180
+ unless @syntax_highlighting.keys.include?(text)
181
+ lex = lexer.lex(text).to_a
182
+ text_size = 0
183
+ @syntax_highlighting[text] = lex.map do |pair|
184
+ {token_type: pair.first, token_text: pair.last}
185
+ end.each do |hash|
186
+ hash[:token_index] = text_size
187
+ text_size += hash[:token_text].size
188
+ end
189
+ end
190
+ @syntax_highlighting[text]
191
+ end
192
+
193
+ def lexer
194
+ require 'rouge'
195
+ # TODO Try to use Rouge::Lexer.find_fancy('guess', code) in the future to guess the language or otherwise detect it from file extension
196
+ @lexer ||= Rouge::Lexer.find_fancy(language)
197
+ @lexer ||= Rouge::Lexer.find_fancy('ruby') # default to Ruby if no lexer is found
198
+ end
199
+
191
200
  def hex_color_to_swt_color(color_data, default_color)
192
201
  color_data = "##{color_data.chars.drop(1).map {|c| c*2}.join}" if color_data.is_a?(String) && color_data.start_with?('#') && color_data&.size == 4
193
202
  color_data = color_data.match(REGEX_COLOR_HEX6).to_a.drop(1).map {|c| "0x#{c}".hex}.to_a if color_data.is_a?(String) && color_data.start_with?('#')
@@ -195,6 +204,20 @@ module Glimmer
195
204
  color_data = default_color if color_data.nil? || color_data.empty?
196
205
  color(*color_data).swt_color
197
206
  end
207
+
208
+ def jump_to_beginning_of_line
209
+ current_line_index = @styled_text_proxy.swt_widget.getLineAtOffset(@styled_text_proxy.swt_widget.getCaretOffset)
210
+ beginning_of_current_line_offset = @styled_text_proxy.swt_widget.getOffsetAtLine(current_line_index)
211
+ @styled_text_proxy.swt_widget.setSelection(beginning_of_current_line_offset, beginning_of_current_line_offset)
212
+ end
213
+
214
+ def jump_to_end_of_line
215
+ current_line_index = @styled_text_proxy.swt_widget.getLineAtOffset(@styled_text_proxy.swt_widget.getCaretOffset)
216
+ current_line = @styled_text_proxy.swt_widget.getLine(current_line_index)
217
+ beginning_of_current_line_offset = @styled_text_proxy.swt_widget.getOffsetAtLine(current_line_index)
218
+ new_offset = beginning_of_current_line_offset + current_line.size
219
+ @styled_text_proxy.swt_widget.setSelection(new_offset, new_offset)
220
+ end
198
221
  end
199
222
  end
200
223
  end
@@ -29,10 +29,7 @@ module Glimmer
29
29
  end
30
30
 
31
31
  def clear_shapes
32
- shapes.dup.each do |shape|
33
- shape.paint_listener_proxy&.unregister
34
- shapes.delete(shape)
35
- end
32
+ shapes.dup.each(&:dispose)
36
33
  end
37
34
 
38
35
  def resetup_shape_painting
@@ -78,7 +78,17 @@ module Glimmer
78
78
  @flyweight_method_names ||= {}
79
79
  end
80
80
 
81
+ def pattern(*args)
82
+ found_pattern = flyweigh_patterns[args]
83
+ if found_pattern.nil? || found_pattern.is_disposed
84
+ found_pattern = flyweigh_patterns[args] = org.eclipse.swt.graphics.Pattern.new(*args)
85
+ end
86
+ found_pattern
87
+ end
81
88
 
89
+ def flyweigh_patterns
90
+ @flyweigh_patterns ||= {}
91
+ end
82
92
  end
83
93
 
84
94
  attr_reader :parent, :name, :args, :options, :paint_listener_proxy
@@ -110,6 +120,14 @@ module Glimmer
110
120
  @options[:round]
111
121
  end
112
122
 
123
+ def has_some_background?
124
+ @properties.keys.map(&:to_s).include?('background') || @properties.keys.map(&:to_s).include?('background_pattern')
125
+ end
126
+
127
+ def has_some_foreground?
128
+ @properties.keys.map(&:to_s).include?('foreground') || @properties.keys.map(&:to_s).include?('foreground_pattern')
129
+ end
130
+
113
131
  def post_add_content
114
132
  amend_method_name_options_based_on_properties
115
133
  setup_painting
@@ -148,7 +166,7 @@ module Glimmer
148
166
  end
149
167
  end
150
168
  new_args = [DisplayProxy.instance.swt_display] + args
151
- args[0] = org.eclipse.swt.graphics.Pattern.new(*new_args)
169
+ args[0] = pattern(*new_args, type: method_name.to_s.match(/set(.+)Pattern/)[1])
152
170
  args[1..-1] = []
153
171
  end
154
172
  args
@@ -173,7 +191,7 @@ module Glimmer
173
191
  args[0] = ImageProxy.new(args[0])
174
192
  end
175
193
  if method_name.include?('image') && args.first.is_a?(ImageProxy)
176
- args[0] = args[0].swt_image
194
+ @image = args[0] = args[0].swt_image
177
195
  end
178
196
  end
179
197
 
@@ -189,10 +207,16 @@ module Glimmer
189
207
  end
190
208
 
191
209
  def amend_method_name_options_based_on_properties
192
- if @properties.keys.map(&:to_s).include?('background') && !@properties.keys.map(&:to_s).include?('foreground')
210
+ if has_some_background? && !has_some_foreground?
193
211
  @options[:fill] = true
194
- elsif @properties.keys.map(&:to_s).include?('foreground') && !@properties.keys.map(&:to_s).include?('background')
212
+ elsif !has_some_background? && has_some_foreground?
195
213
  @options[:fill] = false
214
+ elsif @name == 'rectangle' && has_some_background? && has_some_foreground?
215
+ @options[:fill] = true
216
+ @options[:gradient] = true
217
+ end
218
+ if @name == 'rectangle' && @args.size > 4 && @args.last.is_a?(Numeric)
219
+ @options[:round] = true
196
220
  end
197
221
  @method_name = self.class.method_name(@name, @args + [@options])
198
222
  end
@@ -213,6 +237,26 @@ module Glimmer
213
237
  @properties.symbolize_keys[attribute_name.to_s.to_sym]
214
238
  end
215
239
 
240
+ def pattern(*args, type: nil)
241
+ instance_variable_name = "@#{type}_pattern"
242
+ the_pattern = instance_variable_get(instance_variable_name)
243
+ if the_pattern.nil?
244
+ the_pattern = self.class.pattern(*args)
245
+ end
246
+ the_pattern
247
+ end
248
+
249
+ def dispose
250
+ paint_listener_proxy&.unregister
251
+ @background_pattern&.dispose
252
+ @background_pattern = nil
253
+ @foreground_pattern&.dispose
254
+ @foreground_pattern = nil
255
+ @image&.dispose
256
+ @image = nil
257
+ @parent.shapes.delete(self)
258
+ end
259
+
216
260
  def setup_painting
217
261
  # TODO consider moving this method to parent (making the logic polymorphic)
218
262
  return if @parent.is_disposed
@@ -226,8 +270,8 @@ module Glimmer
226
270
  end
227
271
 
228
272
  def paint(paint_event)
229
- @properties['background'] = [@parent.background] if fill? && !@properties.keys.map(&:to_s).include?('background')
230
- @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !@properties.keys.map(&:to_s).include?('foreground')
273
+ @properties['background'] = [@parent.background] if fill? && !has_some_background?
274
+ @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
231
275
  @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
232
276
  @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
233
277
  @properties.each do |property, args|
@@ -71,6 +71,9 @@ module Glimmer
71
71
  Display.app_name ||= 'Glimmer'
72
72
  @swt_display = Display.new(*args)
73
73
  @swt_display.set_data('proxy', self)
74
+ on_swt_Dispose {
75
+ clear_shapes
76
+ }
74
77
  end
75
78
 
76
79
  def content(&block)
@@ -88,6 +91,14 @@ module Glimmer
88
91
  def timer_exec(&block)
89
92
  @swt_display.timer_exec(&block)
90
93
  end
94
+
95
+ def on_widget_disposed(&block)
96
+ on_swt_Dispose(&block)
97
+ end
98
+
99
+ def disposed?
100
+ @swt_display.isDisposed
101
+ end
91
102
 
92
103
  def method_missing(method, *args, &block)
93
104
  if can_handle_observation_request?(method)
@@ -83,6 +83,13 @@ module Glimmer
83
83
  @swt_image = Image.new(*@args)
84
84
  @original_image_data = @image_data = @swt_image.image_data
85
85
  end
86
+ @swt_image.singleton_class.alias_method(:dispose_without_glimmer, :dispose)
87
+ proxy = self
88
+ # TODO consider adding a get_data/set_data method to conform with other SWT widgets
89
+ @swt_image.singleton_class.define_method(:dispose) do
90
+ proxy.clear_shapes
91
+ dispose_without_glimmer
92
+ end
86
93
  post_add_content if content.nil?
87
94
  end
88
95
 
@@ -120,6 +127,10 @@ module Glimmer
120
127
  @gc = org.eclipse.swt.graphics.GC.new(swt_image)
121
128
  end
122
129
 
130
+ def disposed?
131
+ @swt_image.isDisposed
132
+ end
133
+
123
134
  def has_attribute?(attribute_name, *args)
124
135
  @swt_image.respond_to?(attribute_setter(attribute_name), args) || respond_to?(ruby_attribute_setter(attribute_name), args)
125
136
  end