glimmer-dsl-tk 0.0.32 → 0.0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -40,7 +40,7 @@ module Glimmer
40
40
 
41
41
  def handle_listener(listener_name, &listener)
42
42
  case listener_name.to_s.downcase
43
- when 'change'
43
+ when 'change', 'changed', 'modified'
44
44
  tk.textvariable.trace('write') {
45
45
  listener.call(@tk.textvariable)
46
46
  }
@@ -36,6 +36,7 @@ module Glimmer
36
36
 
37
37
  def post_add_content
38
38
  set_attribute('iconphoto', File.expand_path('../../../icons/glimmer.png', __dir__)) if @tk.iconphoto.nil?
39
+ super
39
40
  end
40
41
 
41
42
  def open
@@ -27,59 +27,106 @@ module Glimmer
27
27
  #
28
28
  # Follows the Proxy Design Pattern
29
29
  class TextProxy < WidgetProxy
30
+ ALL_TAG = '__all__'
31
+ FORMAT_DEFAULT_MAP = {
32
+ 'justify' => 'left',
33
+ }
34
+
30
35
  def handle_listener(listener_name, &listener)
31
36
  case listener_name.to_s.downcase
32
37
  when '<<modified>>', '<modified>', 'modified'
33
38
  modified_listener = Proc.new do |*args|
39
+ @modified_count ||= 0
40
+ @modified_count += 1
34
41
  listener.call(*args)
42
+ @insert_mark_moved_proc&.call
35
43
  @tk.modified = false
36
44
  end
37
- bind('<Modified>', modified_listener)
45
+ @tk.bind('<Modified>', modified_listener)
38
46
  when '<<selection>>', '<selection>', 'selection'
39
- bind('<Selection>', listener)
47
+ @tk.bind('<Selection>', listener)
40
48
  when 'destroy'
41
49
  super
42
- else
43
- @tk.tag_add('__all__', '1.0', 'end') unless @tk.tag_names.include?('__all__')
44
- # TODO make listener pass an event that has a modifiers attribute for easy representation of :shift, :meta, :control, etc... while a letter button is pressed
45
- begin
46
- @tk.tag_bind('__all__', listener_name, &listener)
47
- rescue => e
48
- Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
49
- Glimmer::Config.logger.debug {e.full_message}
50
- listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
51
- listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
52
- @tk.tag_bind('__all__', listener_name, &listener)
50
+ when 'insertmarkmove', 'insertmarkmoved', 'insert_mark_move', 'insert_mark_moved'
51
+ if @insert_mark_moved_proc.nil?
52
+ handle_listener('KeyPress') do |event|
53
+ @insert_mark_moved_proc&.call
54
+ end
55
+ handle_listener('KeyRelease') do |event|
56
+ @insert_mark_moved_proc&.call
57
+ end
58
+ handle_listener('ButtonPress') do |event|
59
+ @insert_mark_moved_proc&.call
60
+ end
61
+ handle_listener('ButtonRelease') do |event|
62
+ @insert_mark_moved_proc&.call
63
+ end
64
+ end
65
+ @insert_mark = @tk.index('insert')
66
+ @insert_mark_moved_proc = Proc.new do
67
+ new_insert_mark = @tk.index('insert')
68
+ if new_insert_mark != @insert_mark
69
+ @insert_mark = new_insert_mark
70
+ listener.call(new_insert_mark)
71
+ end
53
72
  end
73
+ else
74
+ super
54
75
  end
55
76
  end
56
-
57
- def add_selection_format(option, value)
58
- process_selection_ranges { |range_start, range_end| add_format(range_start, range_end, option, value) }
77
+
78
+ def edit_undo
79
+ # <Modified> fires twice the first time, which is equivalent to one change.
80
+ if @modified_count.to_i > 2
81
+ # must count the extra 2 modified count that will occur upon undo too
82
+ @modified_count -= 4
83
+ @tk.edit_undo
84
+ end
85
+ end
86
+
87
+ def edit_redo
88
+ begin
89
+ @tk.edit_redo
90
+ rescue => e
91
+ # No Op
92
+ end
93
+ end
94
+
95
+ def add_selection_format(option, value, no_selection_default: :insert_word)
96
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| add_format(range_start, range_end, option, value) }
59
97
  end
60
98
 
61
- def remove_selection_format(option, value)
62
- process_selection_ranges { |range_start, range_end| remove_format(range_start, range_end, option, value) }
99
+ def remove_selection_format(option, value, no_selection_default: :insert_word)
100
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| remove_format(range_start, range_end, option, value) }
63
101
  end
64
102
 
65
- def toggle_selection_format(option, value)
66
- process_selection_ranges { |range_start, range_end| toggle_format(range_start, range_end, option, value) }
103
+ def toggle_selection_format(option, value, no_selection_default: :insert_word)
104
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| toggle_format(range_start, range_end, option, value) }
67
105
  end
68
106
 
69
- def add_selection_font_format(option, value)
70
- process_selection_ranges { |range_start, range_end| add_font_format(range_start, range_end, option, value) }
107
+ def add_selection_font_format(option, value, no_selection_default: :insert_word)
108
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| add_font_format(range_start, range_end, option, value) }
71
109
  end
72
110
 
73
- def remove_selection_font_format(option, value)
74
- process_selection_ranges { |range_start, range_end| remove_font_format(range_start, range_end, option, value) }
111
+ def remove_selection_font_format(option, value, no_selection_default: :insert_word)
112
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| remove_font_format(range_start, range_end, option, value) }
75
113
  end
76
114
 
77
- def toggle_selection_font_format(option, value)
78
- process_selection_ranges { |range_start, range_end| toggle_font_format(range_start, range_end, option, value) }
115
+ def toggle_selection_font_format(option, value, no_selection_default: :insert_word)
116
+ process_selection_ranges(no_selection_default: no_selection_default) { |range_start, range_end| toggle_font_format(range_start, range_end, option, value) }
79
117
  end
80
118
 
81
- def process_selection_ranges(&processor)
82
- @tk.tag_ranges('sel').each do |region|
119
+ def process_selection_ranges(no_selection_default: :insert_word, &processor)
120
+ regions = @tk.tag_ranges('sel')
121
+ if regions.empty?
122
+ case no_selection_default
123
+ when :insert_word
124
+ regions = [[@tk.index('insert wordstart'), @tk.index('insert wordend + 1 char')]]
125
+ when :insert_letter
126
+ regions = [[@tk.index('insert'), @tk.index('insert + 1 char')]]
127
+ end
128
+ end
129
+ regions.each do |region|
83
130
  range_start = region.first
84
131
  range_end = region.last
85
132
  processor.call(range_start, range_end)
@@ -91,7 +138,7 @@ module Glimmer
91
138
  end
92
139
 
93
140
  def applied_format_tags(region_start, region_end, option, value)
94
- tag_names = @tk.tag_names - ['sel']
141
+ tag_names = @tk.tag_names - ['sel', ALL_TAG]
95
142
 
96
143
  tag_names.select do |tag_name|
97
144
  @tk.tag_ranges(tag_name).any? do |range|
@@ -102,9 +149,26 @@ module Glimmer
102
149
  end
103
150
  end
104
151
 
152
+ def applied_format_value(text_index = nil, option)
153
+ text_index ||= @tk.index('insert')
154
+ region_start = text_index
155
+ region_end = text_index
156
+ tag_names = @tk.tag_names - ['sel', ALL_TAG]
157
+
158
+ values = tag_names.map do |tag_name|
159
+ @tk.tag_ranges(tag_name).map do |range|
160
+ if text_index_less_than_or_equal_to_other_text_index?(range.first, region_start) && text_index_greater_than_or_equal_to_other_text_index?(range.last, region_end)
161
+ @tk.tag_cget(tag_name, option)
162
+ end
163
+ end
164
+ end.flatten.reject {|value| value.to_s.empty?}
165
+
166
+ values.last || (@tk.send(option) rescue FORMAT_DEFAULT_MAP[option])
167
+ end
168
+
105
169
  def add_format(region_start, region_end, option, value)
106
170
  @@tag_number = 0 unless defined?(@@tag_number)
107
- tag = "tag#{@@tag_number += 1}"
171
+ tag = "tag_#{option}_#{@@tag_number += 1}"
108
172
  @tk.tag_configure(tag, {option => value})
109
173
  @tk.tag_add(tag, region_start, region_end)
110
174
  tag
@@ -155,15 +219,14 @@ module Glimmer
155
219
  def applied_font_format_tags_and_regions(region_start, region_end)
156
220
  lines = value.split("\n")
157
221
  tags_and_regions = []
158
- all_tag_names = @tk.tag_names - ['sel']
222
+ all_tag_names = (@tk.tag_names - ['sel', ALL_TAG]).select {|tag_name| tag_name.include?('_font_')}
159
223
  (region_start.to_i..region_end.to_i).each do |line_number|
160
224
  start_character_index = 0
161
225
  start_character_index = region_start.to_s.split('.').last.to_i if line_number == region_start.to_i
162
- end_character_index = lines[line_number - 1].size
226
+ end_character_index = lines[line_number - 1].to_s.size
163
227
  end_character_index = region_end.to_s.split('.').last.to_i if line_number == region_end.to_i
164
228
  (start_character_index...end_character_index).each do |character_index|
165
229
  text_index = "#{line_number}.#{character_index}"
166
- # TODO reimplement the following using @tk.tag_names without arg since passing an arg seems broken and returns inaccurate results
167
230
  region_tag = all_tag_names.reverse.find do |tag|
168
231
  @tk.tag_cget(tag, 'font') && @tk.tag_ranges(tag).any? do |range_start, range_end|
169
232
  text_index_less_than_or_equal_to_other_text_index?(range_start, text_index) && text_index_greater_than_or_equal_to_other_text_index?(range_end, text_index)
@@ -179,6 +242,27 @@ module Glimmer
179
242
  end
180
243
  tags_and_regions
181
244
  end
245
+
246
+ def applied_font_format_value(text_index = nil, font_option)
247
+ text_index ||= @tk.index('insert')
248
+ region_start = text_index
249
+ region_end = @tk.index("#{text_index} + 1 chars")
250
+ tag_names = applied_font_format_tags_and_regions(region_start, region_end).map(&:first)
251
+
252
+ values = tag_names.map do |tag_name|
253
+ @tk.tag_ranges(tag_name).map do |range|
254
+ if text_index_less_than_or_equal_to_other_text_index?(range.first, region_start) && text_index_greater_than_or_equal_to_other_text_index?(range.last, region_end)
255
+ @tk.tag_cget(tag_name, 'font')
256
+ end
257
+ end
258
+ end.flatten.reject {|value| value.to_s.empty?}
259
+
260
+ font = values.last
261
+
262
+ value = font && font.send(font_option)
263
+
264
+ value || Hash[@tk.font.actual][font_option]
265
+ end
182
266
 
183
267
  def add_font_format(region_start, region_end, font_option, value)
184
268
  applied_font_format_tags_and_regions(region_start, region_end).each do |tag, tag_region_start, tag_region_end|
@@ -32,6 +32,19 @@ module Glimmer
32
32
  DEFAULT_HEIGHT = 95
33
33
 
34
34
  attr_reader :tk
35
+ attr_accessor :escapable
36
+ alias escapable? escapable
37
+
38
+ def post_add_content
39
+ if escapable?
40
+ on('KeyPress') do |event|
41
+ if event.keysym == 'Escape'
42
+ grab_release
43
+ destroy
44
+ end
45
+ end
46
+ end
47
+ end
35
48
 
36
49
  def has_attribute?(attribute, *args)
37
50
  %w[width height x y].include?(attribute.to_s) || super
@@ -114,6 +127,17 @@ module Glimmer
114
127
  destroy
115
128
  end
116
129
  end
130
+
131
+ def mac_style=(mac_class, mac_attribute_list = nil)
132
+ if OS.mac?
133
+ @mac_style = [mac_class, mac_attribute_list]
134
+ ::Tk.tk_call("::tk::unsupported::MacWindowStyle", "style", @tk, *@mac_style.compact)
135
+ end
136
+ end
137
+
138
+ def mac_style
139
+ @mac_style
140
+ end
117
141
  end
118
142
  end
119
143
  end
@@ -460,14 +460,20 @@ module Glimmer
460
460
  parent_proxy.handle_listener(listener_name, &listener) if parent_proxy
461
461
  # TODO return a listener registration object that has a deregister method
462
462
  else
463
+ @listeners ||= {}
463
464
  begin
464
- @tk.bind(listener_name, &listener)
465
+ @listeners[listener_name] ||= []
466
+ @tk.bind(listener_name) { |event| @listeners[listener_name].each {|l| l.call(event)} } if @listeners[listener_name].empty?
467
+ @listeners[listener_name] << listener
465
468
  rescue => e
469
+ @listeners.delete(listener_name)
466
470
  Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
467
471
  Glimmer::Config.logger.debug {e.full_message}
468
472
  listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
469
473
  listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
470
- @tk.bind(listener_name, &listener)
474
+ @listeners[listener_name] ||= []
475
+ @tk.bind(listener_name) { |event| @listeners[listener_name].each {|l| l.call(event)} } if @listeners[listener_name].empty?
476
+ @listeners[listener_name] << listener
471
477
  end
472
478
  end
473
479
  end
@@ -56,7 +56,7 @@ class MetaSample
56
56
 
57
57
  def run_sample(sample)
58
58
  Thread.new do
59
- command = "ruby -r #{glimmer_dsl_tk_file} #{sample} 2>&1"
59
+ command = "#{RbConfig.ruby} -r #{glimmer_dsl_tk_file} #{sample} 2>&1"
60
60
  result = ''
61
61
  IO.popen(command) do |f|
62
62
  f.each_line do |line|
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020-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
@@ -107,11 +107,6 @@ class HelloText
107
107
  frame {
108
108
  grid row: 0, column: 0
109
109
 
110
- label {
111
- grid row: 0, column: 0, columnspan: 17
112
- text 'Select a region of text and then apply formatting from the toolbar'
113
- }
114
-
115
110
  column_index = -1
116
111
 
117
112
  combobox {
@@ -143,7 +138,7 @@ class HelloText
143
138
  orient 'vertical'
144
139
  }
145
140
 
146
- button {
141
+ @bold_button = button {
147
142
  grid row: 1, column: column_index += 1, column_weight: 0
148
143
  text 'B'
149
144
  style font: {weight: 'bold'}
@@ -153,7 +148,7 @@ class HelloText
153
148
  end
154
149
  }
155
150
 
156
- button {
151
+ @italic_button = button {
157
152
  grid row: 1, column: column_index += 1, column_weight: 0
158
153
  text 'I'
159
154
  style font: {slant: 'italic'}
@@ -163,7 +158,7 @@ class HelloText
163
158
  end
164
159
  }
165
160
 
166
- button {
161
+ @underline_button = button {
167
162
  grid row: 1, column: column_index += 1, column_weight: 0
168
163
  text 'U'
169
164
  style font: {underline: true}
@@ -172,36 +167,36 @@ class HelloText
172
167
  @text.toggle_selection_font_format('underline', true)
173
168
  end
174
169
  }
175
-
170
+
176
171
  separator {
177
172
  grid row: 1, column: column_index += 1, column_weight: 0
178
173
  orient 'vertical'
179
174
  }
180
175
 
181
- button {
176
+ @justify_left_button = button {
182
177
  grid row: 1, column: column_index += 1, column_weight: 0
183
- image File.expand_path("images/cut.png", __dir__), subsample: 32
178
+ image File.expand_path("images/align-left.png", __dir__), subsample: 32
184
179
 
185
180
  on('command') do
186
- @text.text_cut
181
+ @text.add_selection_format('justify', 'left')
187
182
  end
188
183
  }
189
184
 
190
- button {
185
+ @justify_center_button = button {
191
186
  grid row: 1, column: column_index += 1, column_weight: 0
192
- image File.expand_path("images/copy.png", __dir__), subsample: 32
187
+ image File.expand_path("images/align-center.png", __dir__), subsample: 32
193
188
 
194
189
  on('command') do
195
- @text.text_copy
190
+ @text.add_selection_format('justify', 'center')
196
191
  end
197
192
  }
198
193
 
199
- button {
194
+ @justify_right_button = button {
200
195
  grid row: 1, column: column_index += 1, column_weight: 0
201
- image File.expand_path("images/paste.png", __dir__), subsample: 32
196
+ image File.expand_path("images/align-right.png", __dir__), subsample: 32
202
197
 
203
198
  on('command') do
204
- @text.text_paste
199
+ @text.add_selection_format('justify', 'right')
205
200
  end
206
201
  }
207
202
 
@@ -212,51 +207,51 @@ class HelloText
212
207
 
213
208
  button {
214
209
  grid row: 1, column: column_index += 1, column_weight: 0
215
- image File.expand_path("images/align-left.png", __dir__), subsample: 32
210
+ image File.expand_path("images/picture.png", __dir__), subsample: 32
216
211
 
217
212
  on('command') do
218
- @text.add_selection_format('justify', 'left')
213
+ @text.get_open_file_to_insert_image
219
214
  end
220
215
  }
221
216
 
222
217
  button {
223
218
  grid row: 1, column: column_index += 1, column_weight: 0
224
- image File.expand_path("images/align-center.png", __dir__), subsample: 32
219
+ image File.expand_path("images/search.png", __dir__), subsample: 32
225
220
 
226
221
  on('command') do
227
- @text.add_selection_format('justify', 'center')
222
+ show_find_dialog
228
223
  end
229
224
  }
230
225
 
226
+ separator {
227
+ grid row: 1, column: column_index += 1, column_weight: 0
228
+ orient 'vertical'
229
+ }
230
+
231
231
  button {
232
232
  grid row: 1, column: column_index += 1, column_weight: 0
233
- image File.expand_path("images/align-right.png", __dir__), subsample: 32
233
+ image File.expand_path("images/cut.png", __dir__), subsample: 32
234
234
 
235
235
  on('command') do
236
- @text.add_selection_format('justify', 'right')
236
+ @text.text_cut
237
237
  end
238
238
  }
239
239
 
240
- separator {
241
- grid row: 1, column: column_index += 1, column_weight: 0
242
- orient 'vertical'
243
- }
244
-
245
240
  button {
246
241
  grid row: 1, column: column_index += 1, column_weight: 0
247
- image File.expand_path("images/undo.png", __dir__), subsample: 32
242
+ image File.expand_path("images/copy.png", __dir__), subsample: 32
248
243
 
249
244
  on('command') do
250
- @text.edit_undo
245
+ @text.text_copy
251
246
  end
252
247
  }
253
248
 
254
249
  button {
255
250
  grid row: 1, column: column_index += 1, column_weight: 0
256
- image File.expand_path("images/redo.png", __dir__), subsample: 32
251
+ image File.expand_path("images/paste.png", __dir__), subsample: 32
257
252
 
258
253
  on('command') do
259
- @text.edit_redo
254
+ @text.text_paste
260
255
  end
261
256
  }
262
257
 
@@ -265,21 +260,22 @@ class HelloText
265
260
  orient 'vertical'
266
261
  }
267
262
 
263
+
268
264
  button {
269
265
  grid row: 1, column: column_index += 1, column_weight: 0
270
- image File.expand_path("images/picture.png", __dir__), subsample: 32
266
+ image File.expand_path("images/undo.png", __dir__), subsample: 32
271
267
 
272
268
  on('command') do
273
- @text.get_open_file_to_insert_image
269
+ @text.edit_undo
274
270
  end
275
271
  }
276
272
 
277
273
  button {
278
274
  grid row: 1, column: column_index += 1, column_weight: 0
279
- image File.expand_path("images/search.png", __dir__), subsample: 32
275
+ image File.expand_path("images/redo.png", __dir__), subsample: 32
280
276
 
281
277
  on('command') do
282
- show_find_dialog
278
+ @text.edit_redo
283
279
  end
284
280
  }
285
281
  }
@@ -290,6 +286,19 @@ class HelloText
290
286
  undo true
291
287
  value <=> [self, :document]
292
288
 
289
+ on('InsertMarkMoved') do
290
+ self.font_family = @text.applied_font_format_value('family')
291
+ self.font_size = @text.applied_font_format_value('size')
292
+ @bold_button.default = @text.applied_font_format_value('weight') == 'bold' ? 'active' : 'normal'
293
+ @italic_button.default = @text.applied_font_format_value('slant') == 'italic' ? 'active' : 'normal'
294
+ @underline_button.default = @text.applied_font_format_value('underline') == true ? 'active' : 'normal'
295
+ self.background = @text.applied_format_value('background')
296
+ self.foreground = @text.applied_format_value('foreground')
297
+ @justify_left_button.default = @text.applied_format_value('justify') == 'left' ? 'active' : 'normal'
298
+ @justify_center_button.default = @text.applied_format_value('justify') == 'center' ? 'active' : 'normal'
299
+ @justify_right_button.default = @text.applied_format_value('justify') == 'right' ? 'active' : 'normal'
300
+ end
301
+
293
302
  on('KeyPress') do |event|
294
303
  show_find_dialog if (event.keysym == 'f') && ((OS.mac? && event.state == 8) || (!OS.mac? && event.state == 4))
295
304
  end
@@ -318,7 +327,7 @@ class HelloText
318
327
  end
319
328
  end
320
329
  ]
321
-
330
+
322
331
  on('KeyPress') do |event|
323
332
  if event.keysym == 'Return'
324
333
  find