glimmer-dsl-tk 0.0.26 → 0.0.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/README.md +804 -61
- 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 -10
- data/lib/glimmer/tk/text_proxy.rb +210 -50
- data/lib/glimmer/tk/widget_proxy.rb +23 -8
- data/samples/elaborate/meta_sample.rb +6 -6
- data/samples/hello/hello_built_in_dialog.rb +68 -0
- data/samples/hello/hello_drag_and_drop.rb +159 -0
- data/samples/hello/hello_message_box.rb +0 -4
- data/samples/hello/hello_separator.rb +69 -0
- data/samples/hello/hello_text.rb +202 -23
- data/samples/hello/images/align-center.png +0 -0
- data/samples/hello/images/align-left.png +0 -0
- data/samples/hello/images/align-right.png +0 -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 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.30
|
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,16 +29,6 @@ module Glimmer
|
|
29
29
|
# Follows the Proxy Design Pattern
|
30
30
|
class LabelProxy < WidgetProxy
|
31
31
|
include TextVariableOwner
|
32
|
-
|
33
|
-
FONTS_PREDEFINED = %w[default text fixed menu heading caption small_caption icon tooltip]
|
34
|
-
|
35
|
-
def font=(value)
|
36
|
-
if (value.is_a?(Symbol) || value.is_a?(String)) && FONTS_PREDEFINED.include?(value.to_s.downcase)
|
37
|
-
@tk.font = "tk_#{value}_font".camelcase(:upper)
|
38
|
-
else
|
39
|
-
super
|
40
|
-
end
|
41
|
-
end
|
42
32
|
end
|
43
33
|
end
|
44
34
|
end
|
@@ -43,22 +43,6 @@ module Glimmer
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
def text=(value)
|
47
|
-
if value != @text
|
48
|
-
if @text && value.start_with?(@text)
|
49
|
-
insert('end', value[@text.size..-1])
|
50
|
-
else
|
51
|
-
delete('1.0', 'end')
|
52
|
-
insert('end', value)
|
53
|
-
end
|
54
|
-
@text = value
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def text
|
59
|
-
@text = get("1.0", 'end')
|
60
|
-
end
|
61
|
-
|
62
46
|
def add_selection_format(option, value)
|
63
47
|
process_selection_ranges { |range_start, range_end| add_format(range_start, range_end, option, value) }
|
64
48
|
end
|
@@ -100,7 +84,7 @@ module Glimmer
|
|
100
84
|
|
101
85
|
tag_names.select do |tag_name|
|
102
86
|
@tk.tag_ranges(tag_name).any? do |range|
|
103
|
-
if range.first
|
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)
|
104
88
|
@tk.tag_cget(tag_name, option) == value
|
105
89
|
end
|
106
90
|
end
|
@@ -120,7 +104,7 @@ module Glimmer
|
|
120
104
|
@tk.tag_ranges(tag_name).any? do |range|
|
121
105
|
if range.first.to_f.between?(region_start.to_f, region_end.to_f) or
|
122
106
|
range.last.to_f.between?(region_start.to_f, region_end.to_f) or
|
123
|
-
(range.first
|
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))
|
124
108
|
@tk.tag_cget(tag_name, option) == value
|
125
109
|
end
|
126
110
|
end
|
@@ -141,47 +125,223 @@ module Glimmer
|
|
141
125
|
add_format(region_start, region_end, option, value)
|
142
126
|
end
|
143
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
|
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
|
144
282
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
# else
|
173
|
-
### ensure adding to previous font combination (perhaps checking widget font too)
|
174
|
-
# add_font_format(region_start, region_end, option, value)
|
175
|
-
# end
|
176
|
-
# end
|
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
|
177
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?
|
330
|
+
end
|
331
|
+
|
178
332
|
private
|
179
333
|
|
180
334
|
def initialize_defaults
|
181
335
|
super
|
336
|
+
self.font = {family: 'Courier New'}
|
337
|
+
self.wrap = 'none'
|
182
338
|
self.padx = 5
|
183
339
|
self.pady = 5
|
184
340
|
end
|
341
|
+
|
342
|
+
def clone_font(font)
|
343
|
+
::TkFont.new(Hash[font.actual])
|
344
|
+
end
|
185
345
|
end
|
186
346
|
end
|
187
347
|
end
|
@@ -34,7 +34,9 @@ module Glimmer
|
|
34
34
|
begin
|
35
35
|
class_name = "#{keyword.camelcase(:upper)}Proxy".to_sym
|
36
36
|
Glimmer::Tk.const_get(class_name)
|
37
|
-
rescue
|
37
|
+
rescue => e
|
38
|
+
Glimmer::Config.logger.debug {"Unable to instantiate custom class name for #{keyword} ... defaulting to Glimmer::Tk::WidgetProxy"}
|
39
|
+
Glimmer::Config.logger.debug {e.full_message}
|
38
40
|
Glimmer::Tk::WidgetProxy
|
39
41
|
end
|
40
42
|
end
|
@@ -54,13 +56,15 @@ module Glimmer
|
|
54
56
|
tk_widget_class = eval(tk_widget_name)
|
55
57
|
break
|
56
58
|
rescue RuntimeError, SyntaxError, NameError => e
|
57
|
-
Glimmer::Config.logger.debug e.full_message
|
59
|
+
Glimmer::Config.logger.debug {e.full_message}
|
58
60
|
end
|
59
61
|
end
|
60
62
|
tk_widget_class if tk_widget_class.respond_to?(:new)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
66
|
+
FONTS_PREDEFINED = %w[default text fixed menu heading caption small_caption icon tooltip]
|
67
|
+
|
64
68
|
attr_reader :parent_proxy, :tk, :args, :keyword, :children
|
65
69
|
|
66
70
|
# Initializes a new Tk Widget
|
@@ -104,6 +108,8 @@ module Glimmer
|
|
104
108
|
@tk.send(attribute_setter(attribute), @tk.send(attribute))
|
105
109
|
result = true
|
106
110
|
rescue => e
|
111
|
+
Glimmer::Config.logger.debug { "No tk attribute setter for #{attribute}" }
|
112
|
+
Glimmer::Config.logger.debug { e.full_message }
|
107
113
|
result = false
|
108
114
|
end
|
109
115
|
result
|
@@ -114,7 +120,8 @@ module Glimmer
|
|
114
120
|
# TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
|
115
121
|
@tk.send(attribute)
|
116
122
|
true
|
117
|
-
rescue
|
123
|
+
rescue => e
|
124
|
+
Glimmer::Config.logger.debug { "No tk attribute getter setter for #{attribute}" }
|
118
125
|
false
|
119
126
|
end
|
120
127
|
end
|
@@ -125,7 +132,8 @@ module Glimmer
|
|
125
132
|
begin
|
126
133
|
@tk.tile_instate(attribute)
|
127
134
|
true
|
128
|
-
rescue
|
135
|
+
rescue => e
|
136
|
+
Glimmer::Config.logger.debug { "No tk state for #{attribute}" }
|
129
137
|
false
|
130
138
|
end
|
131
139
|
else
|
@@ -220,6 +228,8 @@ module Glimmer
|
|
220
228
|
def grid(options = {})
|
221
229
|
options = options.stringify_keys
|
222
230
|
index_in_parent = @parent_proxy.children.index(self)
|
231
|
+
options['rowspan'] = options.delete('row_span') if options.keys.include?('row_span')
|
232
|
+
options['columnspan'] = options.delete('column_span') if options.keys.include?('column_span')
|
223
233
|
options['rowweight'] = options.delete('row_weight') if options.keys.include?('row_weight')
|
224
234
|
options['columnweight'] = options.delete('column_weight') if options.keys.include?('column_weight')
|
225
235
|
options['columnweight'] = options['rowweight'] = options.delete('weight') if options.keys.include?('weight')
|
@@ -238,7 +248,11 @@ module Glimmer
|
|
238
248
|
end
|
239
249
|
|
240
250
|
def font=(value)
|
241
|
-
|
251
|
+
if (value.is_a?(Symbol) || value.is_a?(String)) && FONTS_PREDEFINED.include?(value.to_s.downcase)
|
252
|
+
@tk.font = "tk_#{value}_font".camelcase(:upper)
|
253
|
+
else
|
254
|
+
@tk.font = value.is_a?(TkFont) ? value : TkFont.new(value)
|
255
|
+
end
|
242
256
|
rescue => e
|
243
257
|
Glimmer::Config.logger.debug {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
|
244
258
|
Glimmer::Config.logger.debug {e.full_message}
|
@@ -247,7 +261,7 @@ module Glimmer
|
|
247
261
|
|
248
262
|
def apply_style(options)
|
249
263
|
@@style_number = 0 unless defined?(@@style_number)
|
250
|
-
style = "style#{@@style_number}.#{@tk.class.name.split('::').last}"
|
264
|
+
style = "style#{@@style_number += 1}.#{@tk.class.name.split('::').last}"
|
251
265
|
::Tk::Tile::Style.configure(style, options)
|
252
266
|
@tk.style = style
|
253
267
|
end
|
@@ -367,9 +381,9 @@ module Glimmer
|
|
367
381
|
end,
|
368
382
|
},
|
369
383
|
::Tk::Text => {
|
370
|
-
'
|
384
|
+
'value' => lambda do |observer|
|
371
385
|
handle_listener('modified') do
|
372
|
-
observer.call(
|
386
|
+
observer.call(value)
|
373
387
|
end
|
374
388
|
end,
|
375
389
|
},
|
@@ -410,6 +424,7 @@ module Glimmer
|
|
410
424
|
begin
|
411
425
|
@tk.bind(listener_name, &listener)
|
412
426
|
rescue => e
|
427
|
+
Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
|
413
428
|
Glimmer::Config.logger.debug {e.full_message}
|
414
429
|
listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
|
415
430
|
listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
|
@@ -74,8 +74,8 @@ class MetaSample
|
|
74
74
|
def launch
|
75
75
|
@root = root {
|
76
76
|
title 'Glimmer Meta-Sample'
|
77
|
-
width
|
78
|
-
height
|
77
|
+
width 1280
|
78
|
+
height 720
|
79
79
|
|
80
80
|
frame {
|
81
81
|
grid row: 0, column: 0, column_weight: 0, row_weight: 1
|
@@ -87,7 +87,7 @@ class MetaSample
|
|
87
87
|
|
88
88
|
on('command') do
|
89
89
|
@selected_sample_index = index
|
90
|
-
@code_text.
|
90
|
+
@code_text.value = File.read(file_path_for(selected_sample))
|
91
91
|
end
|
92
92
|
}
|
93
93
|
end
|
@@ -102,7 +102,7 @@ class MetaSample
|
|
102
102
|
parent_dir = File.join(Dir.home, '.glimmer-dsl-tk', 'samples', 'hello')
|
103
103
|
FileUtils.mkdir_p(parent_dir)
|
104
104
|
sample_file = File.join(parent_dir, "#{selected_sample.underscore}.rb")
|
105
|
-
File.write(sample_file, @code_text.
|
105
|
+
File.write(sample_file, @code_text.value)
|
106
106
|
FileUtils.cp_r(File.expand_path('../../icons', __dir__), File.dirname(File.dirname(parent_dir)))
|
107
107
|
FileUtils.cp_r(File.expand_path('../hello/images', __dir__), parent_dir)
|
108
108
|
sample_namespace_directory = File.expand_path("../hello/#{selected_sample.underscore}", __dir__)
|
@@ -120,7 +120,7 @@ class MetaSample
|
|
120
120
|
text 'Reset'
|
121
121
|
|
122
122
|
on('command') do
|
123
|
-
@code_text.
|
123
|
+
@code_text.value = File.read(file_path_for(selected_sample))
|
124
124
|
end
|
125
125
|
}
|
126
126
|
}
|
@@ -128,7 +128,7 @@ class MetaSample
|
|
128
128
|
|
129
129
|
@code_text = text {
|
130
130
|
grid row: 0, column: 1, column_weight: 1
|
131
|
-
|
131
|
+
value File.read(file_path_for(selected_sample))
|
132
132
|
}
|
133
133
|
}
|
134
134
|
@root.open
|