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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +835 -122
- data/VERSION +1 -1
- data/glimmer-dsl-tk.gemspec +0 -0
- data/lib/glimmer/dsl/tk/built_in_dialog_expression.rb +57 -0
- data/lib/glimmer/dsl/tk/dsl.rb +1 -0
- data/lib/glimmer/tk/drag_and_drop_extension.rb +112 -0
- data/lib/glimmer/tk/label_proxy.rb +0 -9
- data/lib/glimmer/tk/root_proxy.rb +10 -34
- data/lib/glimmer/tk/text_proxy.rb +285 -9
- data/lib/glimmer/tk/widget_proxy.rb +88 -34
- data/samples/elaborate/meta_sample.rb +6 -6
- data/samples/hello/hello_built_in_dialog.rb +68 -0
- data/samples/hello/hello_combobox.rb +2 -1
- data/samples/hello/hello_drag_and_drop.rb +159 -0
- data/samples/hello/hello_entry.rb +2 -2
- data/samples/hello/hello_message_box.rb +0 -4
- data/samples/hello/hello_separator.rb +69 -0
- data/samples/hello/hello_text.rb +246 -0
- data/samples/hello/images/copy.png +0 -0
- data/samples/hello/images/cut.png +0 -0
- data/samples/hello/images/paste.png +0 -0
- data/samples/hello/images/picture.png +0 -0
- data/samples/hello/images/redo.png +0 -0
- data/samples/hello/images/search.png +0 -0
- data/samples/hello/images/undo.png +0 -0
- metadata +19 -6
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.29
|
data/glimmer-dsl-tk.gemspec
CHANGED
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
|
data/lib/glimmer/dsl/tk/dsl.rb
CHANGED
@@ -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
|
-
|
74
|
+
geometry.split(REGEX_GEOMETRY)[0].to_i
|
101
75
|
end
|
102
76
|
|
103
77
|
def height
|
104
|
-
|
78
|
+
geometry.split(REGEX_GEOMETRY)[1].to_i
|
105
79
|
end
|
106
80
|
|
107
81
|
def x
|
108
|
-
|
82
|
+
sign_number(x_sign, geometry.split(REGEX_GEOMETRY)[2].to_i)
|
109
83
|
end
|
110
84
|
|
111
85
|
def y
|
112
|
-
|
86
|
+
sign_number(y_sign, geometry.split(REGEX_GEOMETRY)[3].to_i)
|
113
87
|
end
|
114
88
|
|
115
89
|
def width=(value)
|
116
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
55
|
-
|
56
|
-
|
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
|
-
|
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
|