glimmer-dsl-swt 4.17.2.2 → 4.17.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ require 'glimmer/ui/custom_widget'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ module Custom
6
+ # CodeText is a customization of StyledText with support for Ruby Syntax Highlighting
7
+ class CodeText
8
+ include Glimmer::UI::CustomWidget
9
+
10
+ SYNTAX_COLOR_MAP = {
11
+ Builtin: [215,58,73],
12
+ Class: [3,47,98],
13
+ Constant: [0,92,197],
14
+ Double: [0,92,197],
15
+ Escape: [:red],
16
+ Function: [:blue],
17
+ Instance: [227,98,9],
18
+ Integer: [:blue],
19
+ Interpol: [:blue],
20
+ Keyword: [:blue],
21
+ Name: [111,66,193], #purple
22
+ Operator: [:red],
23
+ Pseudo: [:dark_red],
24
+ Punctuation: [:blue],
25
+ Single: [106,115,125], # Also, Comments
26
+ Symbol: [:dark_green],
27
+ Text: [75, 75, 75],
28
+ }
29
+
30
+ # TODO support `option :language`
31
+ # TODO support auto language detection
32
+
33
+ def text=(value)
34
+ swt_widget&.text = value
35
+ end
36
+
37
+ def text
38
+ swt_widget&.text
39
+ end
40
+
41
+ def syntax_highlighting
42
+ return [] if text.to_s.strip.empty?
43
+ code = text
44
+ return @syntax_highlighting if @last_code == code
45
+ @last_code = code
46
+ lexer = Rouge::Lexer.find_fancy('ruby', code)
47
+ lex = lexer.lex(code).to_a
48
+ code_size = 0
49
+ lex_hashes = lex.map do |pair|
50
+ {token_type: pair.first, token_text: pair.last}
51
+ end.each do |hash|
52
+ hash[:token_index] = code_size
53
+ code_size += hash[:token_text].size
54
+ end
55
+ code_lines = code.split("\n")
56
+ line_index = 0
57
+ @syntax_highlighting = code_lines_map = code_lines.reduce({}) do |hash, line|
58
+ line_hashes = []
59
+ line_hashes << lex_hashes.shift while lex_hashes.any? && lex_hashes.first[:token_index].between?(line_index, line_index + line.size)
60
+ hash.merge(line_index => line_hashes).tap do
61
+ line_index += line.size + 1
62
+ end
63
+ end
64
+ end
65
+
66
+ before_body {
67
+ @swt_style = swt_style == 0 ? [:border, :multi, :v_scroll, :h_scroll] : swt_style
68
+ }
69
+
70
+ body {
71
+ styled_text(swt_style) {
72
+ font name: 'Consolas', height: 15
73
+ foreground rgb(75, 75, 75)
74
+ left_margin 5
75
+ top_margin 5
76
+ right_margin 5
77
+ bottom_margin 5
78
+
79
+ on_line_get_style { |line_style_event|
80
+ styles = []
81
+ syntax_highlighting[line_style_event.lineOffset].to_a.each do |token_hash|
82
+ start_index = token_hash[:token_index]
83
+ size = token_hash[:token_text].size
84
+ token_color = SYNTAX_COLOR_MAP[token_hash[:token_type].name] || [:black]
85
+ token_color = color(*token_color).swt_color
86
+ styles << StyleRange.new(start_index, size, token_color, nil)
87
+ end
88
+ line_style_event.styles = styles.to_java(StyleRange) unless styles.empty?
89
+ }
90
+ }
91
+ }
92
+ end
93
+ end
94
+ end
95
+ end
@@ -27,10 +27,20 @@ module Glimmer
27
27
  #
28
28
  # Follows the Proxy Design Pattern
29
29
  class ImageProxy
30
+ class << self
31
+ def create(*args)
32
+ if args.size == 1 && args.first.is_a?(ImageProxy)
33
+ args.first
34
+ else
35
+ new(*args)
36
+ end
37
+ end
38
+ end
39
+
30
40
  include_package 'org.eclipse.swt.graphics'
31
41
 
32
42
  attr_reader :file_path, :jar_file_path, :image_data, :swt_image
33
-
43
+
34
44
  # Initializes a proxy for an SWT Image object
35
45
  #
36
46
  # Takes the same args as the SWT Image class
@@ -38,28 +48,41 @@ module Glimmer
38
48
  # and returns an image object.
39
49
  def initialize(*args)
40
50
  @args = args
41
- @file_path = @args.first if @args.first.is_a?(String) && @args.size == 1
42
- if @file_path
43
- if @file_path.start_with?('uri:classloader')
44
- @jar_file_path = @file_path
45
- @file_path = @jar_file_path.sub(/^uri\:classloader\:/, '').sub('//', '/') # the latter sub is needed for Mac
46
- object = java.lang.Object.new
47
- file_input_stream = object.java_class.resource_as_stream(file_path)
48
- buffered_file_input_stream = java.io.BufferedInputStream.new(file_input_stream)
49
- end
50
- @image_data = ImageData.new(buffered_file_input_stream || @file_path)
51
+ options = @args.last.is_a?(Hash) ? @args.delete_at(-1) : {}
52
+ options[:swt_image] = @args.first if @args.size == 1 && @args.first.is_a?(Image)
53
+ @file_path = @args.first if @args.size == 1 && @args.first.is_a?(String)
54
+ @args = @args.first if @args.size == 1 && @args.first.is_a?(Array)
55
+ if options&.keys&.include?(:swt_image)
56
+ @swt_image = options[:swt_image]
57
+ @image_data = @swt_image.image_data
58
+ elsif @file_path
59
+ @image_data = ImageData.new(input_stream || @file_path)
51
60
  @swt_image = Image.new(DisplayProxy.instance.swt_display, @image_data)
52
61
  else
53
62
  @swt_image = Image.new(*@args)
54
63
  @image_data = @swt_image.image_data
55
64
  end
56
65
  end
66
+
67
+ def input_stream
68
+ if @file_path.start_with?('uri:classloader')
69
+ @jar_file_path = @file_path
70
+ file_path = @jar_file_path.sub(/^uri\:classloader\:/, '').sub('//', '/') # the latter sub is needed for Mac
71
+ object = java.lang.Object.new
72
+ file_input_stream = object.java_class.resource_as_stream(file_path)
73
+ else
74
+ file_input_stream = java.io.FileInputStream.new(@file_path)
75
+ end
76
+ java.io.BufferedInputStream.new(file_input_stream) if file_input_stream
77
+ end
57
78
 
58
79
  def scale_to(width, height)
59
80
  scaled_image_data = image_data.scaledTo(width, height)
60
81
  device = swt_image.device
61
82
  swt_image.dispose
62
83
  @swt_image = Image.new(device, scaled_image_data)
84
+ @image_data = @swt_image.image_data
85
+ self
63
86
  end
64
87
 
65
88
  def method_missing(method, *args, &block)
@@ -26,7 +26,7 @@ require 'glimmer/swt/shell_proxy'
26
26
 
27
27
  module Glimmer
28
28
  module SWT
29
- # Proxy for org.eclipse.swt.widgets.Shell
29
+ # Proxy for org.eclipse.swt.widgets.MessageBox
30
30
  #
31
31
  # Follows the Proxy Design Pattern
32
32
  class MessageBoxProxy
@@ -0,0 +1,53 @@
1
+ # Copyright (c) 2007-2020 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
+ require 'glimmer/swt/widget_proxy'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ # Proxy for org.eclipse.swt.custom.SashForm
27
+ #
28
+ # Follows the Proxy Design Pattern
29
+ class SashFormProxy < WidgetProxy
30
+ def post_add_content
31
+ swt_widget.setWeights(@weights) unless @weights.nil?
32
+ end
33
+
34
+ def set_attribute(attribute_name, *args)
35
+ if attribute_name.to_s == "weights"
36
+ @weights = args
37
+ @weights = @weights.first if @weights.first.is_a?(Array)
38
+ else
39
+ super(attribute_name, *args)
40
+ end
41
+ end
42
+
43
+ def get_attribute(attribute_name)
44
+ if attribute_name.to_s == "weights"
45
+ swt_widget.getWeights.to_a
46
+ else
47
+ super(attribute_name)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -128,7 +128,7 @@ module Glimmer
128
128
  def deconstruct(integer)
129
129
  constant_source_class.constants.reduce([]) do |found, c|
130
130
  constant_value = constant_source_class.const_get(c) rescue -1
131
- is_found = constant_value.is_a?(Integer) && (integer & constant_value) == integer
131
+ is_found = constant_value.is_a?(Integer) && (integer & constant_value) == constant_value
132
132
  is_found ? found += [c] : found
133
133
  end
134
134
  end
@@ -136,6 +136,7 @@ module Glimmer
136
136
  # Reverse engineer a style integer into a symbol
137
137
  # Useful for debugging
138
138
  def reverse_lookup(integer)
139
+ # TODO support looking up compound style mixes
139
140
  constant_source_class.constants.reduce([]) do |found, c|
140
141
  constant_value = constant_source_class.const_get(c) rescue -1
141
142
  is_found = constant_value.is_a?(Integer) && integer == constant_value
@@ -23,6 +23,7 @@ require 'glimmer/swt/widget_listener_proxy'
23
23
  require 'glimmer/swt/color_proxy'
24
24
  require 'glimmer/swt/font_proxy'
25
25
  require 'glimmer/swt/swt_proxy'
26
+ require 'glimmer/swt/display_proxy'
26
27
  require 'glimmer/swt/dnd_proxy'
27
28
  require 'glimmer/swt/image_proxy'
28
29
 
@@ -54,7 +55,7 @@ module Glimmer
54
55
  "radio" => [:radio],
55
56
  "scrolled_composite" => [:border, :h_scroll, :v_scroll],
56
57
  "spinner" => [:border],
57
- "styled_text" => [:border],
58
+ "styled_text" => [:border, :multi, :v_scroll, :h_scroll],
58
59
  "table" => [:virtual, :border, :full_selection],
59
60
  "text" => [:border],
60
61
  "toggle" => [:toggle],
@@ -204,7 +205,7 @@ module Glimmer
204
205
  widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
205
206
  if widget_custom_attribute
206
207
  widget_custom_attribute[:setter][:invoker].call(@swt_widget, args)
207
- elsif @swt_widget.respond_to?(attribute_setter(attribute_name), args)
208
+ elsif @swt_widget.respond_to?(attribute_setter(attribute_name))
208
209
  apply_property_type_converters(attribute_name, args)
209
210
  @swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
210
211
  else
@@ -328,6 +329,57 @@ module Glimmer
328
329
  observer.call(@swt_widget.getText)
329
330
  }
330
331
  end,
332
+ :caret_position => lambda do |observer|
333
+ on_swt_keydown { |event|
334
+ observer.call(@swt_widget.getCaretPosition)
335
+ }
336
+ on_swt_keyup { |event|
337
+ observer.call(@swt_widget.getCaretPosition)
338
+ }
339
+ on_swt_mousedown { |event|
340
+ observer.call(@swt_widget.getCaretPosition)
341
+ }
342
+ on_swt_mouseup { |event|
343
+ observer.call(@swt_widget.getCaretPosition)
344
+ }
345
+ end,
346
+ :selection => lambda do |observer|
347
+ on_swt_keydown { |event|
348
+ observer.call(@swt_widget.getSelection)
349
+ }
350
+ on_swt_keyup { |event|
351
+ observer.call(@swt_widget.getSelection)
352
+ }
353
+ on_swt_mousedown { |event|
354
+ observer.call(@swt_widget.getSelection)
355
+ }
356
+ on_swt_mouseup { |event|
357
+ observer.call(@swt_widget.getSelection)
358
+ }
359
+ end,
360
+ :selection_count => lambda do |observer|
361
+ on_swt_keydown { |event|
362
+ observer.call(@swt_widget.getSelectionCount)
363
+ }
364
+ on_swt_keyup { |event|
365
+ observer.call(@swt_widget.getSelectionCount)
366
+ }
367
+ on_swt_mousedown { |event|
368
+ observer.call(@swt_widget.getSelectionCount)
369
+ }
370
+ on_swt_mouseup { |event|
371
+ observer.call(@swt_widget.getSelectionCount)
372
+ }
373
+ end,
374
+ :top_index => lambda do |observer|
375
+ @last_top_index = @swt_widget.getTopIndex
376
+ on_paint_control { |event|
377
+ if @swt_widget.getTopIndex != @last_top_index
378
+ @last_top_index = @swt_widget.getTopIndex
379
+ observer.call(@last_top_index)
380
+ end
381
+ }
382
+ end,
331
383
  },
332
384
  Java::OrgEclipseSwtWidgets::Button => {
333
385
  :selection => lambda do |observer|
@@ -619,7 +671,11 @@ module Glimmer
619
671
  },
620
672
  'selection_count' => {
621
673
  getter: {name: 'getSelectionCount'},
622
- setter: {name: 'setSelection', invoker: lambda { |widget, args| @swt_widget.setSelection(@swt_widget.getCaretPosition, @swt_widget.getCaretPosition + args.first) if args.first }},
674
+ setter: {name: 'setSelection', invoker: lambda { |widget, args|
675
+ # TODO consider the idea of aliasing getCaretPosition in StyledText
676
+ caret_position = @swt_widget.getCaretPosition rescue @swt_widget.getCaretOffset
677
+ @swt_widget.setSelection(caret_position, caret_position + args.first) if args.first
678
+ }},
623
679
  },
624
680
  }
625
681
  end
@@ -683,21 +739,45 @@ module Glimmer
683
739
  },
684
740
  :background => color_converter,
685
741
  :background_image => lambda do |value|
686
- image_proxy = nil
687
- if value.is_a?(String)
688
- image_proxy = ImageProxy.new(value)
689
- elsif value.is_a?(Array)
690
- image_proxy = ImageProxy.new(*value)
691
- end
692
- if image_proxy
742
+ image_proxy = ImageProxy.create(value)
743
+
744
+ if image_proxy&.file_path&.end_with?('.gif')
745
+ image = image_proxy.swt_image
746
+ width = image.get_bounds.width.to_i
747
+ height = image.get_bounds.height.to_i
748
+ image_number = 0
749
+ loader = ImageLoader.new
750
+ loader.load(image_proxy.input_stream)
751
+ image.dispose
752
+ image = org.eclipse.swt.graphics.Image.new(DisplayProxy.instance.swt_display,loader.data[0].scaledTo(width, height))
753
+ gc = org.eclipse.swt.graphics.GC.new(image)
754
+ on_paint_control { |event|
755
+ image_number = (image_number == loader.data.length - 1) ? 0 : image_number + 1
756
+ next_frame_data = loader.data[image_number]
757
+ image = org.eclipse.swt.graphics.Image.new(DisplayProxy.instance.swt_display, next_frame_data.scaledTo(width, height))
758
+ event.gc.drawImage(image, 0, 0, width, height, 0, 0, width, height)
759
+ image.dispose
760
+ }
761
+ Thread.new {
762
+ last_image_number = -1
763
+ while last_image_number != image_number
764
+ last_image_number = image_number
765
+ sync_exec {
766
+ redraw
767
+ }
768
+ delayTime = loader.data[image_number].delayTime.to_f / 100.0
769
+ sleep(delayTime)
770
+ end
771
+ };
772
+ image_proxy = nil
773
+ else
693
774
  on_swt_Resize do |resize_event|
694
775
  image_proxy.scale_to(@swt_widget.getSize.x, @swt_widget.getSize.y)
695
- @swt_widget.setBackgroundImage(image_proxy.swt_image)
696
- end
697
- image_proxy.swt_image
698
- else
699
- value
700
- end
776
+ @swt_widget.setBackgroundImage(image_proxy.swt_image)
777
+ end
778
+ end
779
+
780
+ image_proxy&.swt_image
701
781
  end,
702
782
  :cursor => lambda do |value|
703
783
  cursor_proxy = nil
@@ -718,34 +798,18 @@ module Glimmer
718
798
  end
719
799
  end,
720
800
  :image => lambda do |value|
721
- if value.is_a?(String)
722
- ImageProxy.new(value).swt_image
723
- elsif value.is_a?(Array)
724
- ImageProxy.new(*value).swt_image
725
- else
726
- value
727
- end
801
+ ImageProxy.create(value).swt_image
728
802
  end,
729
803
  :images => lambda do |array|
730
804
  array.to_a.map do |value|
731
- if value.is_a?(String)
732
- ImageProxy.new(value).swt_image
733
- elsif value.is_a?(Array)
734
- ImageProxy.new(*value).swt_image
735
- else
736
- value
737
- end
805
+ ImageProxy.create(value).swt_image
738
806
  end.to_java(Image)
739
807
  end,
740
808
  :items => lambda do |value|
741
809
  value.to_java :string
742
810
  end,
743
811
  :text => lambda do |value|
744
- if swt_widget.is_a?(Browser)
745
- value.to_s
746
- else
747
- value.to_s
748
- end
812
+ value.to_s
749
813
  end,
750
814
  :transfer => lambda do |value|
751
815
  value = value.first if value.is_a?(Array) && value.size == 1 && value.first.is_a?(Array)
@@ -0,0 +1,166 @@
1
+ class Sample
2
+ attr_accessor :sample_directory, :file, :selected
3
+
4
+ def initialize(file, sample_directory: )
5
+ self.file = file
6
+ self.sample_directory = sample_directory
7
+ end
8
+
9
+ def name
10
+ if @name.nil?
11
+ @name = File.basename(file, '.rb').split('_').map(&:capitalize).join(' ')
12
+ if @name.start_with?('Hello')
13
+ name_parts = @name.split
14
+ name_parts[0] = name_parts.first + ','
15
+ name_parts[-1] = name_parts.last + '!'
16
+ @name = name_parts.join(' ')
17
+ end
18
+ end
19
+ @name
20
+ end
21
+
22
+ def content
23
+ @content ||= File.read(file)
24
+ end
25
+
26
+ def launch
27
+ load file
28
+ end
29
+ end
30
+
31
+ class SampleDirectory
32
+ class << self
33
+ attr_accessor :selected_sample
34
+
35
+ def sample_directories
36
+ if @sample_directories.nil?
37
+ @sample_directories = Dir.glob(File.join(File.expand_path('..', __FILE__), '*')).
38
+ select { |file| File.directory?(file) }.
39
+ map { |file| SampleDirectory.new(file) }
40
+ glimmer_gems = Gem.find_latest_files("glimmer-*-*")
41
+ sample_directories = glimmer_gems.map do |lib|
42
+ File.dirname(File.dirname(lib))
43
+ end.select do |gem|
44
+ Dir.exist?(File.join(gem, 'samples'))
45
+ end.map do |gem|
46
+ Dir.glob(File.join(gem, 'samples', '*')).select {|file_or_dir| Dir.exist?(file_or_dir)}
47
+ end.flatten.uniq.reverse
48
+ if Dir.exist?('samples')
49
+ Dir.glob(File.join('samples', '*')).to_a.reverse.each do |dir|
50
+ sample_directories << dir if Dir.exist?(dir)
51
+ end
52
+ end
53
+ sample_directories = sample_directories.uniq {|dir| File.basename(dir)}
54
+ @sample_directories = sample_directories.map { |file| SampleDirectory.new(file) }
55
+ end
56
+ @sample_directories
57
+ end
58
+
59
+ def all_samples
60
+ @all_samples ||= sample_directories.map(&:samples).reduce(:+)
61
+ end
62
+ end
63
+
64
+ include Glimmer # used for observe syntax
65
+
66
+ attr_accessor :file
67
+
68
+ def initialize(file)
69
+ self.file = file
70
+ end
71
+
72
+ def name
73
+ File.basename(file).split('_').map(&:capitalize).join(' ')
74
+ end
75
+
76
+ def samples
77
+ if @samples.nil?
78
+ @samples = Dir.glob(File.join(file, '*')).
79
+ select { |file| File.file?(file) }.
80
+ map { |sample_file| Sample.new(sample_file, sample_directory: self) }.
81
+ sort_by(&:name)
82
+
83
+ @samples.each do |sample|
84
+ observe(sample, :selected) do |new_selected_value|
85
+ if new_selected_value
86
+ self.class.all_samples.reject {|a_sample| a_sample.name == sample.name}.each do |other_sample|
87
+ other_sample.selected = false
88
+ end
89
+ self.class.selected_sample = sample
90
+ end
91
+ end
92
+ end
93
+ end
94
+ @samples
95
+ end
96
+ end
97
+
98
+ class MetaSampleApplication
99
+ include Glimmer
100
+
101
+ def launch
102
+ shell {
103
+ text 'Glimmer Meta-Sample (The Sample of Samples)'
104
+
105
+ on_swt_show {
106
+ SampleDirectory.selected_sample = SampleDirectory.all_samples.first
107
+ }
108
+
109
+ sash_form {
110
+ composite {
111
+ grid_layout 1, false
112
+
113
+ scrolled_composite {
114
+ layout_data(:fill, :fill, true, true)
115
+
116
+ composite {
117
+ SampleDirectory.sample_directories.each { |sample_directory|
118
+ group {
119
+ layout_data(:fill, :fill, true, true)
120
+ grid_layout 2, false
121
+ text sample_directory.name
122
+ font height: 30
123
+
124
+ sample_directory.samples.each { |sample|
125
+ label_radio = radio {
126
+ selection bind(sample, :selected)
127
+ }
128
+ label {
129
+ text sample.name
130
+ font height: 30
131
+
132
+ on_mouse_up {
133
+ sample.selected = true
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ }
141
+
142
+ button {
143
+ layout_data(:center, :center, false, false) {
144
+ height_hint 150
145
+ }
146
+ text 'Launch Sample'
147
+ font height: 45
148
+ on_widget_selected {
149
+ SampleDirectory.selected_sample.launch
150
+ }
151
+ }
152
+ }
153
+
154
+ code_text {
155
+ text bind(SampleDirectory, 'selected_sample.content')
156
+ editable false
157
+ caret nil
158
+ }
159
+
160
+ weights 1, 2
161
+ }
162
+ }.open
163
+ end
164
+ end
165
+
166
+ MetaSampleApplication.new.launch