glimmer-dsl-tk 0.0.26 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|