glimmer-dsl-tk 0.0.25 → 0.0.29

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.25
1
+ 0.0.29
Binary file
@@ -0,0 +1,57 @@
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
+ require 'glimmer'
23
+ require 'glimmer/dsl/expression'
24
+
25
+ module Glimmer
26
+ module DSL
27
+ module Tk
28
+ class BuiltInDialogExpression < Expression
29
+ def can_interpret?(parent, keyword, *args, &block)
30
+ keyword = "get_#{keyword}" if keyword.start_with?('open')
31
+ (keyword.start_with?('get') or keyword.start_with?('choose')) and
32
+ (
33
+ (block.nil? and ::Tk.respond_to?(keyword.camelcase)) or
34
+ keyword == 'choose_font'
35
+ )
36
+ end
37
+
38
+ def interpret(parent, keyword, *args, &block)
39
+ if args.first.is_a?(Hash)
40
+ options = args.first.symbolize_keys
41
+ options[:filetypes] = options.delete(:file_types) if options.keys.include?(:file_types)
42
+ options[:filetypes] = options[:filetypes].map { |key, value| "{#{key}} {#{value}}" } if options[:filetypes].is_a?(Hash)
43
+ options[:parent] = options[:parent].tk if options[:parent].is_a?(Glimmer::Tk::RootProxy)
44
+ args[0] = options
45
+ end
46
+ keyword = "get_#{keyword}" if keyword.start_with?('open') || keyword.start_with?('save') || keyword.start_with?('multiple')
47
+ if keyword == 'choose_font'
48
+ TkFont::Fontchooser.configure(:font => args, :command => block)
49
+ TkFont::Fontchooser.show
50
+ else
51
+ ::Tk.send(keyword.camelcase, *args)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -42,6 +42,7 @@ module Glimmer
42
42
  attribute
43
43
  shine_data_binding
44
44
  widget
45
+ built_in_dialog
45
46
  ]
46
47
  )
47
48
  end
@@ -0,0 +1,112 @@
1
+ require "json"
2
+
3
+ module Glimmer
4
+ module Tk
5
+ class WidgetProxy
6
+ attr_accessor :on_drag_motion_block
7
+
8
+ def drag_source=(value)
9
+ @drag_source = value
10
+ if @drag_source
11
+ make_draggable
12
+ else
13
+ make_non_draggable
14
+ end
15
+ end
16
+
17
+ def on_drag_start_block=(block)
18
+ @on_drag_start_block = block
19
+ make_draggable
20
+ end
21
+
22
+ def on_drop_block=(value)
23
+ @on_drop_block = value
24
+ self.tk.bind("<DropEvent>", proc { |tk_event|
25
+ drop_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
26
+ @on_drop_block.call(drop_event) if self.tk == drop_event.target
27
+ })
28
+ self.tk.bind("<DropCheckEvent>", proc { |tk_event|
29
+ drop_check_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
30
+ drop_check_event.source.event_generate("<DropAcceptedEvent>")
31
+ })
32
+ end
33
+
34
+ def textvariable_defined?
35
+ tk_widget_has_attribute_setter?(:textvariable) && !tk.textvariable.nil?
36
+ end
37
+
38
+ def make_draggable
39
+ drag_event = nil
40
+ bind("<DropAcceptedEvent>", proc { |event| drag_event.drop_accepted = true })
41
+ bind("B1-Motion", proc { |tk_event|
42
+ if drag_event.nil?
43
+ tooltip = TkToplevel.new(root).overrideredirect(1) #create tooltip window to display dragged data
44
+ tooltip.geometry("+#{tk_event.x_root + 10}+#{tk_event.y_root - 2}")
45
+ drag_event = DragAndDropEvent.new(self.tk, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
46
+ if @drag_source
47
+ tk_event.widget.configure(:cursor => "hand2")
48
+ # Default data to drag is text
49
+ drag_event.data = if textvariable_defined? then tk.textvariable.value elsif has_attribute?(:text) then tk.text end
50
+ TkLabel.new(tooltip) { text drag_event.data }.pack
51
+ elsif !@on_drag_start_block.nil?
52
+ @on_drag_start_block.call(drag_event)
53
+ TkLabel.new(tooltip) { text drag_event.data }.pack if tooltip.winfo_children().length == 0
54
+ end
55
+ else
56
+ drag_event.x_root, drag_event.y_root = tk_event.x_root, tk_event.y_root
57
+ drag_event.drop_accepted = false
58
+ move_over_widget = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
59
+ drag_event.target = move_over_widget
60
+ move_over_widget.event_generate("<DropCheckEvent>", :data => drag_event.to_json)
61
+ if @on_drag_motion_block.nil?
62
+ # Default motion behavior:
63
+ # 1.Change cursor to show whether text can be dropped.
64
+ # 2.Move tooltip with dragged data.
65
+ if drag_event.drop_accepted
66
+ tk_event.widget.configure(:cursor => "hand1")
67
+ else
68
+ tk_event.widget.configure(:cursor => "hand2")
69
+ end
70
+ drag_event.tooltip.geometry("+#{tk_event.x_root + 10}+#{tk_event.y_root - 2}")
71
+ else
72
+ @on_drag_motion_block.call(drag_event)
73
+ end
74
+ end
75
+ })
76
+ bind("ButtonRelease-1", proc { |tk_event|
77
+ if drag_event
78
+ drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
79
+ drag_event.source.configure(:cursor => "")
80
+ drag_event.target.event_generate("<DropEvent>", :data => drag_event.to_json)
81
+ drag_event.tooltip.destroy
82
+ drag_event = nil
83
+ end
84
+ })
85
+ end
86
+
87
+ def make_non_draggable
88
+ @tk.bind_remove("B1-Motion")
89
+ @tk.bind_remove("ButtonRelease-1")
90
+ @tk.bind_remove("<DropAcceptedEvent>")
91
+ end
92
+
93
+ DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
94
+ def as_json(*)
95
+ klass = self.class.name
96
+ {
97
+ JSON.create_id => klass,
98
+ "v" => [values[0].object_id, values[1].object_id, values[2].object_id].concat(values.drop 3),
99
+ }
100
+ end
101
+
102
+ def to_json(*args)
103
+ as_json.to_json(*args)
104
+ end
105
+
106
+ def self.json_create(object)
107
+ new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]), ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -29,15 +29,6 @@ module Glimmer
29
29
  # Follows the Proxy Design Pattern
30
30
  class LabelProxy < WidgetProxy
31
31
  include TextVariableOwner
32
-
33
- def set_attribute(attribute, *args)
34
- if attribute.to_s == 'font'
35
- args[0] = "tk_#{args[0]}_font".camelcase(:upper) if (args[0].is_a?(Symbol) || args[0].is_a?(String)) && args[0].to_s == args[0].to_s.downcase
36
- super
37
- else
38
- super
39
- end
40
- end
41
32
  end
42
33
  end
43
34
  end
@@ -59,16 +59,6 @@ module Glimmer
59
59
  when 'iconphoto'
60
60
  args[0..-1] = [image_argument(args)]
61
61
  super
62
- when 'width'
63
- @width = args.first.to_i
64
- self.geometry = "#{args.first.to_i}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
65
- when 'height'
66
- @height = args.first.to_i
67
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{args.first.to_i}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
68
- when 'x'
69
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{args.first.to_i > 0 ? '+' : '-'}#{args.first.to_i.abs}#{y_sign}#{abs_y}"
70
- when 'y'
71
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{args.first.to_i > 0 ? '+' : '-'}#{args.first.to_i.abs}"
72
62
  when 'resizable'
73
63
  if args.size == 1 && !args.first.is_a?(Array)
74
64
  self.resizable = [args.first]*2
@@ -80,52 +70,38 @@ module Glimmer
80
70
  end
81
71
  end
82
72
 
83
- def get_attribute(attribute)
84
- attribute = attribute.to_s
85
- case attribute
86
- when 'width'
87
- geometry.split(REGEX_GEOMETRY)[0].to_i
88
- when 'height'
89
- geometry.split(REGEX_GEOMETRY)[1].to_i
90
- when 'x'
91
- sign_number(x_sign, geometry.split(REGEX_GEOMETRY)[2].to_i)
92
- when 'y'
93
- sign_number(y_sign, geometry.split(REGEX_GEOMETRY)[3].to_i)
94
- else
95
- super
96
- end
97
- end
98
-
99
73
  def width
100
- get_attribute(:width)
74
+ geometry.split(REGEX_GEOMETRY)[0].to_i
101
75
  end
102
76
 
103
77
  def height
104
- get_attribute(:height)
78
+ geometry.split(REGEX_GEOMETRY)[1].to_i
105
79
  end
106
80
 
107
81
  def x
108
- get_attribute(:x)
82
+ sign_number(x_sign, geometry.split(REGEX_GEOMETRY)[2].to_i)
109
83
  end
110
84
 
111
85
  def y
112
- get_attribute(:y)
86
+ sign_number(y_sign, geometry.split(REGEX_GEOMETRY)[3].to_i)
113
87
  end
114
88
 
115
89
  def width=(value)
116
- set_attribute(:width, value)
90
+ @width = value.to_i
91
+ self.geometry = "#{value.to_i}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
117
92
  end
118
93
 
119
94
  def height=(value)
120
- set_attribute(:height, value)
95
+ @height = value.to_i
96
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{value.to_i}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
121
97
  end
122
98
 
123
99
  def x=(value)
124
- set_attribute(:x, value)
100
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}#{y_sign}#{abs_y}"
125
101
  end
126
102
 
127
103
  def y=(value)
128
- set_attribute(:y, value)
104
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}"
129
105
  end
130
106
 
131
107
  def handle_listener(listener_name, &listener)
@@ -43,29 +43,305 @@ module Glimmer
43
43
  end
44
44
  end
45
45
 
46
- def text=(value)
47
- if value != @text
48
- @text = value
49
- delete('1.0', 'end')
50
- insert('end', value)
46
+ def add_selection_format(option, value)
47
+ process_selection_ranges { |range_start, range_end| add_format(range_start, range_end, option, value) }
48
+ end
49
+
50
+ def remove_selection_format(option, value)
51
+ process_selection_ranges { |range_start, range_end| remove_format(range_start, range_end, option, value) }
52
+ end
53
+
54
+ def toggle_selection_format(option, value)
55
+ process_selection_ranges { |range_start, range_end| toggle_format(range_start, range_end, option, value) }
56
+ end
57
+
58
+ def add_selection_font_format(option, value)
59
+ process_selection_ranges { |range_start, range_end| add_font_format(range_start, range_end, option, value) }
60
+ end
61
+
62
+ def remove_selection_font_format(option, value)
63
+ process_selection_ranges { |range_start, range_end| remove_font_format(range_start, range_end, option, value) }
64
+ end
65
+
66
+ def toggle_selection_font_format(option, value)
67
+ process_selection_ranges { |range_start, range_end| toggle_font_format(range_start, range_end, option, value) }
68
+ end
69
+
70
+ def process_selection_ranges(&processor)
71
+ @tk.tag_ranges('sel').each do |region|
72
+ range_start = region.first
73
+ range_end = region.last
74
+ processor.call(range_start, range_end)
51
75
  end
52
76
  end
53
77
 
54
- def text(value = nil)
55
- if value.nil?
56
- @text = get("1.0", 'end')
78
+ def applied_format?(region_start, region_end, option, value)
79
+ !applied_format_tags(region_start, region_end, option, value).empty?
80
+ end
81
+
82
+ def applied_format_tags(region_start, region_end, option, value)
83
+ tag_names = @tk.tag_names - ['sel']
84
+
85
+ tag_names.select do |tag_name|
86
+ @tk.tag_ranges(tag_name).any? do |range|
87
+ 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)
88
+ @tk.tag_cget(tag_name, option) == value
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def add_format(region_start, region_end, option, value)
95
+ @@tag_number = 0 unless defined?(@@tag_number)
96
+ tag = "tag#{@@tag_number += 1}"
97
+ @tk.tag_configure(tag, {option => value})
98
+ @tk.tag_add(tag, region_start, region_end)
99
+ tag
100
+ end
101
+
102
+ def remove_format(region_start, region_end, option, value)
103
+ partial_intersection_option_applied_tags = tag_names.select do |tag_name|
104
+ @tk.tag_ranges(tag_name).any? do |range|
105
+ if range.first.to_f.between?(region_start.to_f, region_end.to_f) or
106
+ range.last.to_f.between?(region_start.to_f, region_end.to_f) or
107
+ (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))
108
+ @tk.tag_cget(tag_name, option) == value
109
+ end
110
+ end
111
+ end
112
+
113
+ partial_intersection_option_applied_tags.each do |tag_name|
114
+ @tk.tag_remove(tag_name, region_start, region_end)
115
+ end
116
+
117
+ nil
118
+ end
119
+
120
+ # toggles option/value tag (removes if already applied)
121
+ def toggle_format(region_start, region_end, option, value)
122
+ if applied_format?(region_start, region_end, option, value)
123
+ remove_format(region_start, region_end, option, value)
57
124
  else
58
- self.text = value
125
+ add_format(region_start, region_end, option, value)
126
+ end
127
+ end
128
+
129
+ # TODO Algorithm for font option formatting
130
+ # for a region, grab all the latest tags for each subregion as well as the widget font for subregions without a tag
131
+ # for each part of the region covered by a tag, augment its font with new font option (or remove if that is what is needed)
132
+ # Once add and remove are implemented, implement toggle
133
+ # Also, there is a need for a method that checks if a font option value applies to an entire region (to decide which way to toggle with toggle method)
134
+ def applied_font_format?(region_start, region_end, font_option, value)
135
+ applied_font_format_tags_and_regions(region_start, region_end).all? do |tag, region_start, region_end|
136
+ if tag.nil?
137
+ @tk.font.send(font_option) == value
138
+ else
139
+ @tk.tag_cget(tag, 'font').send(font_option) == value
140
+ end
141
+ end
142
+ end
143
+
144
+ def applied_font_format_tags_and_regions(region_start, region_end)
145
+ lines = value.split("\n")
146
+ tags_and_regions = []
147
+ all_tag_names = @tk.tag_names - ['sel']
148
+ (region_start.to_i..region_end.to_i).each do |line_number|
149
+ start_character_index = 0
150
+ start_character_index = region_start.to_s.split('.').last.to_i if line_number == region_start.to_i
151
+ end_character_index = lines[line_number - 1].size
152
+ end_character_index = region_end.to_s.split('.').last.to_i if line_number == region_end.to_i
153
+ (start_character_index...end_character_index).each do |character_index|
154
+ text_index = "#{line_number}.#{character_index}"
155
+ # TODO reimplement the following using @tk.tag_names without arg since passing an arg seems broken and returns inaccurate results
156
+ region_tag = all_tag_names.reverse.find do |tag|
157
+ @tk.tag_cget(tag, 'font') && @tk.tag_ranges(tag).any? do |range_start, range_end|
158
+ 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)
159
+ end
160
+ end
161
+ end_text_index = add_to_text_index(text_index, 1)
162
+ if tags_and_regions&.last && region_tag == tags_and_regions.last.first
163
+ tags_and_regions.last[2] = end_text_index
164
+ else
165
+ tags_and_regions << [region_tag, text_index, end_text_index]
166
+ end
167
+ end
59
168
  end
169
+ tags_and_regions
170
+ end
171
+
172
+ def add_font_format(region_start, region_end, font_option, value)
173
+ applied_font_format_tags_and_regions(region_start, region_end).each do |tag, tag_region_start, tag_region_end|
174
+ if tag
175
+ bigger_region_tag = @tk.tag_ranges(tag).any? do |range_start, range_end|
176
+ text_index_less_than_other_text_index?(range_start, tag_region_start) || text_index_greater_than_other_text_index?(range_end, tag_region_end)
177
+ end
178
+ if bigger_region_tag
179
+ @tk.tag_ranges(tag).each do |range_start, range_end|
180
+ if text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_end, tag_region_start)
181
+ font = @tk.tag_cget(tag, 'font')
182
+ remove_format(range_start, range_end, 'font', font)
183
+ add_format(range_start, tag_region_start, 'font', font)
184
+ font_clone = clone_font(font)
185
+ font_clone.send("#{font_option}=", value)
186
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
187
+ elsif text_index_greater_than_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_start, tag_region_end)
188
+ font = @tk.tag_cget(tag, 'font')
189
+ remove_format(range_start, range_end, 'font', font)
190
+ add_format(tag_region_end, range_end, 'font', font)
191
+ font_clone = clone_font(font)
192
+ font_clone.send("#{font_option}=", value)
193
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
194
+ elsif text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_greater_than_other_text_index?(range_end, tag_region_end)
195
+ font = @tk.tag_cget(tag, 'font')
196
+ remove_format(range_start, range_end, 'font', font)
197
+ add_format(range_start, tag_region_start, 'font', font)
198
+ remove_format(range_start, range_end, 'font', font)
199
+ add_format(tag_region_end, range_end, 'font', font)
200
+ font_clone = clone_font(font)
201
+ font_clone.send("#{font_option}=", value)
202
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
203
+ end
204
+ end
205
+ else
206
+ current_font = @tk.tag_cget(tag, 'font')
207
+ current_font.send("#{font_option}=", value)
208
+ end
209
+ else
210
+ add_format(tag_region_start, tag_region_end, 'font', default_font_attributes.merge(font_option => value))
211
+ end
212
+ end
213
+ end
214
+
215
+ def remove_font_format(region_start, region_end, font_option, value)
216
+ applied_font_format_tags_and_regions(region_start, region_end).each do |tag, tag_region_start, tag_region_end|
217
+ if tag
218
+ bigger_region_tag = @tk.tag_ranges(tag).any? do |range_start, range_end|
219
+ text_index_less_than_other_text_index?(range_start, tag_region_start) || text_index_greater_than_other_text_index?(range_end, tag_region_end)
220
+ end
221
+ if bigger_region_tag
222
+ @tk.tag_ranges(tag).each do |range_start, range_end|
223
+ if text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_end, tag_region_start)
224
+ font = @tk.tag_cget(tag, 'font')
225
+ remove_format(range_start, range_end, 'font', font)
226
+ add_format(range_start, subtract_from_text_index(tag_region_start, 1), 'font', font)
227
+ font_clone = clone_font(font)
228
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
229
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
230
+ elsif text_index_greater_than_other_text_index?(range_end, tag_region_end) && text_index_greater_than_or_equal_to_other_text_index?(range_start, tag_region_start) && text_index_less_than_or_equal_to_other_text_index?(range_start, tag_region_end)
231
+ font = @tk.tag_cget(tag, 'font')
232
+ remove_format(range_start, range_end, 'font', font)
233
+ add_format(add_to_text_index(tag_region_end, 1), range_end, 'font', font)
234
+ font_clone = clone_font(font)
235
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
236
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
237
+ elsif text_index_less_than_other_text_index?(range_start, tag_region_start) && text_index_greater_than_other_text_index?(range_end, tag_region_end)
238
+ font = @tk.tag_cget(tag, 'font')
239
+ remove_format(range_start, range_end, 'font', font)
240
+ add_format(range_start, subtract_from_text_index(tag_region_start, 1), 'font', font)
241
+ remove_format(range_start, range_end, 'font', font)
242
+ add_format(add_to_text_index(tag_region_end, 1), range_end, 'font', font)
243
+ font_clone = clone_font(font)
244
+ font_clone.send("#{font_option}=", default_for_font_option(font_option))
245
+ add_format(tag_region_start, tag_region_end, 'font', font_clone)
246
+ end
247
+ end
248
+ else
249
+ current_font = @tk.tag_cget(tag, 'font')
250
+ current_font.send("#{font_option}=", default_for_font_option(font_option))
251
+ end
252
+ else
253
+ add_format(tag_region_start, tag_region_end, 'font', default_font_attributes.merge(font_option => default_for_font_option(font_option)))
254
+ end
255
+ end
256
+ end
257
+
258
+ # toggles option/value tag (removes if already applied)
259
+ def toggle_font_format(region_start, region_end, option, value)
260
+ if applied_font_format?(region_start, region_end, option, value)
261
+ remove_font_format(region_start, region_end, option, value)
262
+ else
263
+ add_font_format(region_start, region_end, option, value)
264
+ end
265
+ end
266
+
267
+ def default_for_font_option(font_option)
268
+ @tk.font.send(font_option)
269
+ end
270
+
271
+ def default_font_attributes
272
+ Hash[@tk.font.actual]
273
+ end
274
+
275
+ def add_to_text_index(text_index, addition)
276
+ text_index_parts = text_index.split('.')
277
+ line = text_index_parts.first
278
+ char_index = text_index_parts.last
279
+ char_index = char_index.to_i + addition
280
+ "#{line}.#{char_index}"
281
+ end
282
+
283
+ def subtract_from_text_index(text_index, subtraction)
284
+ add_to_text_index(text_index, -1 * subtraction)
285
+ end
286
+
287
+ def text_index_less_than_other_text_index?(region1, region2)
288
+ region1_parts = region1.to_s.split('.')
289
+ region2_parts = region2.to_s.split('.')
290
+ return true if region1_parts.first.to_i < region2_parts.first.to_i
291
+ return false if region1_parts.first.to_i > region2_parts.first.to_i
292
+ region1_parts.last.to_i < region2_parts.last.to_i
293
+ end
294
+
295
+ def text_index_less_than_or_equal_to_other_text_index?(region1, region2)
296
+ region1_parts = region1.to_s.split('.')
297
+ region2_parts = region2.to_s.split('.')
298
+ return true if region1_parts.first.to_i < region2_parts.first.to_i
299
+ return false if region1_parts.first.to_i > region2_parts.first.to_i
300
+ region1_parts.last.to_i <= region2_parts.last.to_i
301
+ end
302
+
303
+ def text_index_greater_than_other_text_index?(region1, region2)
304
+ region1_parts = region1.to_s.split('.')
305
+ region2_parts = region2.to_s.split('.')
306
+ return true if region1_parts.first.to_i > region2_parts.first.to_i
307
+ return false if region1_parts.first.to_i < region2_parts.first.to_i
308
+ region1_parts.last.to_i > region2_parts.last.to_i
309
+ end
310
+
311
+ def text_index_greater_than_or_equal_to_other_text_index?(region1, region2)
312
+ region1_parts = region1.to_s.split('.')
313
+ region2_parts = region2.to_s.split('.')
314
+ return true if region1_parts.first.to_i > region2_parts.first.to_i
315
+ return false if region1_parts.first.to_i < region2_parts.first.to_i
316
+ region1_parts.last.to_i >= region2_parts.last.to_i
317
+ end
318
+
319
+ def insert_image(text_index, *image_args)
320
+ TkTextImage.new(@tk, 'insert', :image => image_argument(image_args))
321
+ end
322
+
323
+ def get_open_file_to_insert_image(text_index = 'insert')
324
+ image_filename = Glimmer::DSL::Tk::BuiltInDialogExpression.new.interpret(nil, 'get_open_file', filetypes: {
325
+ 'PNG Images' => '.png',
326
+ 'Gif Images' => '.gif',
327
+ 'PPM Images' => '.ppm'
328
+ })
329
+ insert_image('insert', image_filename) unless image_filename.nil? || image_filename.to_s.empty?
60
330
  end
61
331
 
62
332
  private
63
333
 
64
334
  def initialize_defaults
65
335
  super
336
+ self.font = {family: 'Courier New'}
337
+ self.wrap = 'none'
66
338
  self.padx = 5
67
339
  self.pady = 5
68
340
  end
341
+
342
+ def clone_font(font)
343
+ ::TkFont.new(Hash[font.actual])
344
+ end
69
345
  end
70
346
  end
71
347
  end