tk_component 0.1.0 → 0.1.1
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/Gemfile +6 -0
- data/Gemfile.lock +16 -5
- data/bin/browser_demo.rb +49 -0
- data/bin/table_view_demo.rb +66 -0
- data/bin/tiles_demo.rb +48 -0
- data/lib/tk_component.rb +5 -0
- data/lib/tk_component/base.rb +49 -3
- data/lib/tk_component/basic_component.rb +8 -0
- data/lib/tk_component/browser_column_component.rb +70 -0
- data/lib/tk_component/browser_component.rb +66 -0
- data/lib/tk_component/builder/grid_map.rb +4 -4
- data/lib/tk_component/builder/node.rb +35 -11
- data/lib/tk_component/builder/tk_item.rb +354 -18
- data/lib/tk_component/menu.rb +4 -0
- data/lib/tk_component/r_browser_component.rb +33 -0
- data/lib/tk_component/table_view_component.rb +90 -0
- data/lib/tk_component/turtle.rb +100 -0
- data/lib/tk_component/version.rb +1 -1
- data/lib/tk_component/window.rb +4 -4
- metadata +16 -6
@@ -35,10 +35,10 @@ module TkComponent
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def set_weights(row, col, weights = {})
|
38
|
-
|
39
|
-
@row_weights[row] = ((rw = @row_weights[row]).present? ? [rw,
|
40
|
-
|
41
|
-
@column_weights[col] = ((cw = @column_weights[col]).present? ? [cw,
|
38
|
+
vw = weights[:y_flex]
|
39
|
+
@row_weights[row] = ((rw = @row_weights[row]).present? ? [rw, vw].max : vw) if vw
|
40
|
+
hw = weights[:x_flex]
|
41
|
+
@column_weights[col] = ((cw = @column_weights[col]).present? ? [cw, hw].max : hw) if hw
|
42
42
|
end
|
43
43
|
|
44
44
|
def row_indexes
|
@@ -1,16 +1,19 @@
|
|
1
1
|
module TkComponent
|
2
2
|
module Builder
|
3
3
|
|
4
|
-
TK_CMDS = %w(label entry button canvas text scale group).to_set.freeze
|
4
|
+
TK_CMDS = %w(label entry button radio_set radio_button canvas text scale group tree tree_node hscroll_bar vscroll_bar hpaned vpaned).to_set.freeze
|
5
5
|
LAYOUT_CMDS = %w(frame hframe vframe row cell).to_set.freeze
|
6
|
-
EVENT_CMDS = %w(on_change on_mouse_down on_mouse_up on_mouse_drag on_mouse_wheel on_click on_event).to_set.freeze
|
6
|
+
EVENT_CMDS = %w(on_change on_mouse_down on_mouse_up on_mouse_drag on_mouse_wheel on_click on_select on_item_open on_event).to_set.freeze
|
7
7
|
TOKENS = (TK_CMDS + LAYOUT_CMDS + EVENT_CMDS).freeze
|
8
8
|
|
9
|
+
LAYOUT_OPTIONS = %i(column row rowspan columnspan sticky x_flex y_flex)
|
10
|
+
|
9
11
|
class Node
|
10
12
|
attr_accessor :name
|
11
13
|
attr_accessor :options
|
12
14
|
attr_accessor :sub_nodes
|
13
15
|
attr_accessor :grid
|
16
|
+
attr_accessor :weights
|
14
17
|
attr_accessor :grid_map
|
15
18
|
attr_accessor :event_handlers
|
16
19
|
attr_accessor :tk_item
|
@@ -29,14 +32,14 @@ module TkComponent
|
|
29
32
|
@name = name
|
30
33
|
@options = options.with_indifferent_access
|
31
34
|
@sub_nodes = []
|
32
|
-
@grid = {}
|
35
|
+
@grid = {}.with_indifferent_access
|
36
|
+
@weights = {}.with_indifferent_access
|
33
37
|
@grid_map = GridMap.new
|
34
38
|
@event_handlers = []
|
35
39
|
@tk_item = nil
|
36
40
|
end
|
37
41
|
|
38
42
|
def short(level = 0)
|
39
|
-
puts(" " * level + " #{@name}")
|
40
43
|
@sub_nodes.each do |n|
|
41
44
|
n.short(level + 4)
|
42
45
|
end
|
@@ -44,10 +47,12 @@ module TkComponent
|
|
44
47
|
end
|
45
48
|
|
46
49
|
def insert_component(component_class, parent_component, options = {}, &block)
|
47
|
-
|
50
|
+
layout_options = options.slice(*LAYOUT_OPTIONS)
|
51
|
+
c_node = node_from_command(:frame, layout_options, &block)
|
48
52
|
comp = component_class.new(options.merge(parent: parent_component, parent_node: c_node))
|
49
53
|
comp.generate(parent_component, options)
|
50
54
|
parent_component.add_child(comp)
|
55
|
+
comp
|
51
56
|
end
|
52
57
|
|
53
58
|
def add_event_handler(name, lambda, options = {})
|
@@ -61,9 +66,25 @@ module TkComponent
|
|
61
66
|
sub_nodes.each do |n|
|
62
67
|
n.build(self, parent_component)
|
63
68
|
end
|
69
|
+
apply_grid
|
70
|
+
built
|
71
|
+
end
|
72
|
+
|
73
|
+
def apply_grid
|
64
74
|
self.tk_item.apply_internal_grid(grid_map)
|
65
75
|
end
|
66
76
|
|
77
|
+
def built
|
78
|
+
self.tk_item.built
|
79
|
+
end
|
80
|
+
|
81
|
+
def rebuilt
|
82
|
+
end
|
83
|
+
|
84
|
+
def remove
|
85
|
+
self.tk_item.remove
|
86
|
+
end
|
87
|
+
|
67
88
|
def prepare_option_events(component)
|
68
89
|
option_events = options.extract!(*EVENT_CMDS)
|
69
90
|
option_events.each do |k, v|
|
@@ -74,6 +95,7 @@ module TkComponent
|
|
74
95
|
end
|
75
96
|
|
76
97
|
def prepare_grid
|
98
|
+
self.grid_map = GridMap.new
|
77
99
|
return unless self.sub_nodes.any?
|
78
100
|
current_row = -1
|
79
101
|
current_col = -1
|
@@ -90,13 +112,15 @@ module TkComponent
|
|
90
112
|
current_col = 0 if current_col < 0
|
91
113
|
current_row, current_col = grid_map.get_next_cell(current_row, current_col, going_down)
|
92
114
|
binding.pry if n.options.nil?
|
93
|
-
grid = n.
|
94
|
-
n.grid
|
95
|
-
|
96
|
-
|
115
|
+
n.grid = {}.with_indifferent_access if n.grid.nil?
|
116
|
+
n.grid.merge!(n.options.extract!(:column, :row, :rowspan, :columnspan, :sticky))
|
117
|
+
n.grid.merge!(column: current_col, row: current_row)
|
118
|
+
rowspan = n.grid[:rowspan] || 1
|
119
|
+
columnspan = n.grid[:columnspan] || 1
|
97
120
|
grid_map.fill(current_row, current_col, rowspan, columnspan, true)
|
98
|
-
weights = n.
|
99
|
-
|
121
|
+
n.weights = {}.with_indifferent_access if n.weights.nil?
|
122
|
+
n.weights.merge!(n.options.extract!(:x_flex, :y_flex))
|
123
|
+
grid_map.set_weights(current_row, current_col, n.weights)
|
100
124
|
n.prepare_grid
|
101
125
|
final_sub_nodes << n
|
102
126
|
end
|
@@ -11,34 +11,43 @@ module TkComponent
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
14
|
-
|
15
|
-
raise "Don't know how to create #{name}" unless tk_class
|
16
|
-
@native_item = tk_class.new(parent_item.native_item)
|
14
|
+
@native_item = create_native_item(parent_item.native_item, name, options, grid, event_handlers)
|
17
15
|
apply_options(options)
|
18
16
|
set_grid(grid)
|
19
17
|
set_event_handlers(event_handlers)
|
20
18
|
end
|
21
19
|
|
22
|
-
def
|
20
|
+
def create_native_item(parent_native_item, name, options = {}, grid = {}, event_handlers = [])
|
21
|
+
native_item_class(parent_native_item, name, options, grid, event_handlers).new(parent_native_item)
|
22
|
+
end
|
23
|
+
|
24
|
+
def native_item_class(parent_native_item, name, options = {}, grid = {}, event_handlers = [])
|
25
|
+
tk_class = TK_CLASSES[name.to_sym]
|
26
|
+
raise "Don't know how to create #{name}" unless tk_class.present?
|
27
|
+
return tk_class
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove
|
31
|
+
@native_item.destroy
|
32
|
+
end
|
33
|
+
|
34
|
+
def apply_options(options, to_item = self.native_item)
|
23
35
|
options.each do |k,v|
|
24
|
-
apply_option(k, v)
|
36
|
+
apply_option(k, v, to_item)
|
25
37
|
end
|
26
38
|
end
|
27
39
|
|
28
|
-
def apply_option(option, value)
|
29
|
-
|
40
|
+
def apply_option(option, value, to_item = self.native_item)
|
41
|
+
to_item.public_send(option, value)
|
30
42
|
end
|
31
43
|
|
32
|
-
def set_grid(grid)
|
33
|
-
|
44
|
+
def set_grid(grid, to_item = self.native_item)
|
45
|
+
to_item.grid(grid)
|
34
46
|
end
|
35
47
|
|
36
48
|
def apply_internal_grid(grid_map)
|
37
|
-
puts(grid_map)
|
38
49
|
grid_map.column_indexes.each { |c| TkGrid.columnconfigure(self.native_item, c, weight: grid_map.column_weight(c)) }
|
39
50
|
grid_map.row_indexes.each { |r| TkGrid.rowconfigure(self.native_item, r, weight: grid_map.row_weight(r)) }
|
40
|
-
# grid_map.column_indexes.each { |c| TkGrid.columnconfigure(self.native_item, c, weight: 1) }
|
41
|
-
# grid_map.row_indexes.each { |r| TkGrid.rowconfigure(self.native_item, r, weight: 1) }
|
42
51
|
end
|
43
52
|
|
44
53
|
def set_event_handlers(event_handlers)
|
@@ -55,10 +64,17 @@ module TkComponent
|
|
55
64
|
Event.bind_event(event_handler.name, self, event_handler.options, event_handler.lambda)
|
56
65
|
end
|
57
66
|
end
|
67
|
+
|
68
|
+
def built
|
69
|
+
end
|
70
|
+
|
71
|
+
def focus
|
72
|
+
self.native_item.focus
|
73
|
+
end
|
58
74
|
end
|
59
75
|
|
60
76
|
module ValueTyping
|
61
|
-
def apply_option(option, v)
|
77
|
+
def apply_option(option, v, to_item = self.native_item)
|
62
78
|
case option.to_sym
|
63
79
|
when :value
|
64
80
|
self.value = v
|
@@ -90,15 +106,23 @@ module TkComponent
|
|
90
106
|
attr_accessor :tk_variable
|
91
107
|
|
92
108
|
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
93
|
-
|
109
|
+
create_variable
|
94
110
|
super
|
95
|
-
|
111
|
+
apply_variable
|
96
112
|
end
|
97
113
|
|
98
114
|
def variable_name
|
99
115
|
:variable
|
100
116
|
end
|
101
117
|
|
118
|
+
def apply_variable
|
119
|
+
self.native_item&.public_send(variable_name, @tk_variable)
|
120
|
+
end
|
121
|
+
|
122
|
+
def create_variable
|
123
|
+
@tk_variable = TkVariable.new
|
124
|
+
end
|
125
|
+
|
102
126
|
delegate :value, to: :tk_variable
|
103
127
|
delegate :"value=", to: :tk_variable
|
104
128
|
end
|
@@ -127,8 +151,83 @@ module TkComponent
|
|
127
151
|
end
|
128
152
|
end
|
129
153
|
|
154
|
+
class TkRadioSet < TkItemWithVariable
|
155
|
+
# The variable for the radio set is only to be used by radio buttons inside it
|
156
|
+
# Thus, we don't try to link it to the actual item
|
157
|
+
def apply_variable
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class TkRadioButton < TkItemWithVariable
|
162
|
+
# We need to use the tk_variable created by the parent_item
|
163
|
+
# So we set it here and skip creation below
|
164
|
+
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
165
|
+
@tk_variable = parent_item.tk_variable
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
169
|
+
def create_variable
|
170
|
+
end
|
171
|
+
|
172
|
+
# It is unfortunate that native TK radio buttons use 'value' to
|
173
|
+
# spedify the value for each of them, colliding with the 'value'
|
174
|
+
# methods for our items with variables. Thus, we need to
|
175
|
+
# override the setting of the 'value' option to revert it to the
|
176
|
+
# default functionality
|
177
|
+
def apply_option(option, v, to_item = self.native_item)
|
178
|
+
case option.to_sym
|
179
|
+
when :value
|
180
|
+
to_item.public_send(option, v)
|
181
|
+
else
|
182
|
+
super
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
module Scrollable
|
188
|
+
ROOT_FRAME_OPTIONS = %i|width height relief borderwidth padx pady padding| + TkComponent::Builder::LAYOUT_OPTIONS
|
189
|
+
|
190
|
+
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
191
|
+
return super unless (s_options = options.delete(:scrollers)) && s_options.present? && s_options != 'none'
|
192
|
+
frame_item = TK_CLASSES[:frame].new(parent_item.native_item) # Containing frame
|
193
|
+
real_native_item = create_native_item(frame_item, name, options, grid, event_handlers)
|
194
|
+
f_options = options.extract!(*ROOT_FRAME_OPTIONS)
|
195
|
+
apply_options(f_options, frame_item) # Apply the applicable options to the enclosing frame
|
196
|
+
@native_item = real_native_item
|
197
|
+
apply_options(options, real_native_item)
|
198
|
+
set_grid(grid, frame_item)
|
199
|
+
real_native_item.grid( :column => 0, :row => 0, :sticky => 'nwes')
|
200
|
+
if s_options.include?('x')
|
201
|
+
h_scrollbar = TK_CLASSES[:hscroll_bar].new(frame_item)
|
202
|
+
h_scrollbar.orient('horizontal')
|
203
|
+
h_scrollbar.command proc { |*args| real_native_item.xview(*args) }
|
204
|
+
real_native_item['xscrollcommand'] = proc { |*args| h_scrollbar.set(*args) }
|
205
|
+
h_scrollbar.grid( :column => 0, :row => 1, :sticky => 'wes')
|
206
|
+
end
|
207
|
+
if s_options.include?('y')
|
208
|
+
v_scrollbar = TK_CLASSES[:vscroll_bar].new(frame_item)
|
209
|
+
v_scrollbar.orient('vertical')
|
210
|
+
v_scrollbar.command proc { |*args| real_native_item.yview(*args) }
|
211
|
+
real_native_item['yscrollcommand'] = proc { |*args| v_scrollbar.set(*args) }
|
212
|
+
v_scrollbar.grid( :column => 1, :row => 0, :sticky => 'nse')
|
213
|
+
end
|
214
|
+
TkGrid.columnconfigure(frame_item, 0, :weight => 1)
|
215
|
+
TkGrid.columnconfigure(frame_item, 1, :weight => 0) if v_scrollbar.present?
|
216
|
+
TkGrid.rowconfigure(frame_item, 0, :weight => 1)
|
217
|
+
TkGrid.rowconfigure(frame_item, 1, :weight => 0) if h_scrollbar.present?
|
218
|
+
@native_item = real_native_item
|
219
|
+
set_event_handlers(event_handlers)
|
220
|
+
end
|
221
|
+
|
222
|
+
# We need to remove the parent native item, as it's the container we put in place initially
|
223
|
+
def remove
|
224
|
+
@native_item.winfo_parent.destroy
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
130
228
|
class TkText < TkItem
|
131
229
|
include ValueTyping
|
230
|
+
include Scrollable
|
132
231
|
|
133
232
|
def value
|
134
233
|
native_item.get('1.0', 'end')
|
@@ -138,6 +237,24 @@ module TkComponent
|
|
138
237
|
native_item.replace('1.0', 'end', text)
|
139
238
|
end
|
140
239
|
|
240
|
+
def selected_text
|
241
|
+
ranges = native_item.tag_ranges('sel')
|
242
|
+
return nil if ranges.empty?
|
243
|
+
native_item.get(ranges.first.first, ranges.first.last)
|
244
|
+
end
|
245
|
+
|
246
|
+
def current_line
|
247
|
+
native_item.get('insert linestart', 'insert lineend')
|
248
|
+
end
|
249
|
+
|
250
|
+
def append_text(text)
|
251
|
+
native_item.insert('end', text)
|
252
|
+
end
|
253
|
+
|
254
|
+
def select_range(from, to)
|
255
|
+
native_item.tag_add('sel', from, to)
|
256
|
+
end
|
257
|
+
|
141
258
|
def set_event_handler(event_handler)
|
142
259
|
case event_handler.name
|
143
260
|
when :change
|
@@ -159,11 +276,214 @@ module TkComponent
|
|
159
276
|
end
|
160
277
|
end
|
161
278
|
|
279
|
+
class TkTree < TkItem
|
280
|
+
include Scrollable
|
281
|
+
@column_defs = []
|
282
|
+
|
283
|
+
def apply_options(options, to_item = self.native_item)
|
284
|
+
super
|
285
|
+
return unless @column_defs.present?
|
286
|
+
cols = @column_defs.map { |c| c[:key] }
|
287
|
+
to_item.columns(cols[1..-1].join(' ')) unless cols == ['#0']
|
288
|
+
@column_defs.each.with_index do |cd, idx|
|
289
|
+
key = idx == 0 ? '#0' : cd[:key]
|
290
|
+
column_conf = cd.slice(:width, :anchor)
|
291
|
+
to_item.column_configure(key, column_conf) unless column_conf.empty?
|
292
|
+
heading_conf = cd.slice(:text)
|
293
|
+
to_item.heading_configure(key, heading_conf) unless heading_conf.empty?
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def apply_option(option, v, to_item = self.native_item)
|
298
|
+
case option.to_sym
|
299
|
+
when :column_defs
|
300
|
+
@column_defs = v
|
301
|
+
when :heading
|
302
|
+
@column_defs = [ { key: '#0', text: v } ]
|
303
|
+
else
|
304
|
+
super
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def set_event_handler(event_handler)
|
309
|
+
case event_handler.name
|
310
|
+
when :select
|
311
|
+
Event.bind_event('<TreeviewSelect>', self, event_handler.options, event_handler.lambda)
|
312
|
+
when :item_open
|
313
|
+
Event.bind_event('<TreeviewOpen>', self, event_handler.options, event_handler.lambda)
|
314
|
+
else
|
315
|
+
super
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def scroll_to_selection
|
320
|
+
scroll_to_item(@native_item.selection.first)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Right now it only works well for non-nested trees
|
324
|
+
def scroll_to_item(tree_item)
|
325
|
+
return unless tree_item.present?
|
326
|
+
items = @native_item.children('')
|
327
|
+
rel_pos = items.index(tree_item).to_f / items.size.to_f
|
328
|
+
@native_item.after(200) { @native_item.yview_moveto(rel_pos) }
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
class TkTreeNode < TkItem
|
333
|
+
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
334
|
+
item_options = options.dup
|
335
|
+
parent_node = item_options.delete(:parent) || ''
|
336
|
+
parent_native_item = (parent_node == '' ? '' : parent_node.native_item)
|
337
|
+
at = item_options.delete(:at)
|
338
|
+
selected = item_options.delete(:selected)
|
339
|
+
@native_item = parent_item.native_item.insert(parent_native_item, at, item_options)
|
340
|
+
parent_item.native_item.selection_add(@native_item) if selected
|
341
|
+
set_event_handlers(event_handlers)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
class ScrollBar < TkItem
|
346
|
+
def apply_option(option, v, to_item = self.native_item)
|
347
|
+
case option.to_sym
|
348
|
+
when :linked_to
|
349
|
+
@linked_to = v
|
350
|
+
else
|
351
|
+
super
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def set_event_handler(event_handler)
|
356
|
+
case event_handler.name
|
357
|
+
when :change
|
358
|
+
Event.Event.bind_command(event_handler.name, self, event_handler.options, event_handler.lambda)
|
359
|
+
else
|
360
|
+
super
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def apply_options(options, to_item = self.native_item)
|
365
|
+
options.merge!(orient: orient)
|
366
|
+
super
|
367
|
+
end
|
368
|
+
|
369
|
+
def set_event_handlers(event_handlers)
|
370
|
+
bind_linked_to
|
371
|
+
super
|
372
|
+
end
|
373
|
+
|
374
|
+
def bind_linked_to
|
375
|
+
return unless @linked_to.present?
|
376
|
+
items = @linked_to.is_a?(Array) ? @linked_to.map(&:native_item) : [ @linked_to.native_item ]
|
377
|
+
self.native_item.command proc { |*args|
|
378
|
+
items.each do |item|
|
379
|
+
item.send(scroll_command, *args)
|
380
|
+
end
|
381
|
+
}
|
382
|
+
items.each do |item|
|
383
|
+
item.send(linked_scroll_command, proc { |*args| self.native_item.send(linked_scroll_event, *args) })
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
def orient
|
388
|
+
raise "#{self.class.to_s} shouldn't be instantiated directly. Use 'H' or 'V' subclasses"
|
389
|
+
end
|
390
|
+
|
391
|
+
def scroll_command
|
392
|
+
raise "#{self.class.to_s} shouldn't be instantiated directly. Use 'H' or 'V' subclasses"
|
393
|
+
end
|
394
|
+
|
395
|
+
def linked_scroll_command
|
396
|
+
raise "#{self.class.to_s} shouldn't be instantiated directly. Use 'H' or 'V' subclasses"
|
397
|
+
end
|
398
|
+
|
399
|
+
def linked_scroll_event
|
400
|
+
raise "#{self.class.to_s} shouldn't be instantiated directly. Use 'H' or 'V' subclasses"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
class HScrollbar < ScrollBar
|
405
|
+
def orient
|
406
|
+
'horizontal'
|
407
|
+
end
|
408
|
+
|
409
|
+
def scroll_command
|
410
|
+
:xview
|
411
|
+
end
|
412
|
+
|
413
|
+
def linked_scroll_command
|
414
|
+
:xscrollcommand
|
415
|
+
end
|
416
|
+
|
417
|
+
def linked_scroll_event
|
418
|
+
:set
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
class VScrollbar < ScrollBar
|
423
|
+
def orient
|
424
|
+
'vertical'
|
425
|
+
end
|
426
|
+
|
427
|
+
def scroll_command
|
428
|
+
:yview
|
429
|
+
end
|
430
|
+
|
431
|
+
def linked_scroll_command
|
432
|
+
:yscrollcommand
|
433
|
+
end
|
434
|
+
|
435
|
+
def linked_scroll_event
|
436
|
+
:set
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
class PanedWindow < TkItem
|
441
|
+
def create_native_item(parent_native_item, name, options = {}, grid = {}, event_handlers = [])
|
442
|
+
native_item_class(parent_native_item, name, options, grid, event_handlers).new(parent_native_item, orient: orient)
|
443
|
+
end
|
444
|
+
|
445
|
+
def built
|
446
|
+
# We need to synchronize children items to the panned window
|
447
|
+
added_panes = self.native_item.winfo_children - self.native_item.panes
|
448
|
+
removed_panes = self.native_item.panes - self.native_item.winfo_children
|
449
|
+
added_panes.each do |child|
|
450
|
+
self.native_item.add(child, weight: 1)
|
451
|
+
end
|
452
|
+
removed_panes.each do |child|
|
453
|
+
self.native_item.forget(child)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def orient
|
458
|
+
raise "#{self.class.to_s} shouldn't be instantiated directly. Use 'H' or 'V' subclasses"
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
class HPanedWindow < PanedWindow
|
463
|
+
def orient
|
464
|
+
'horizontal'
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
class VPanedWindow < PanedWindow
|
469
|
+
def orient
|
470
|
+
'vertical'
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
162
474
|
class TkWindow < TkItem
|
163
475
|
def initialize(parent_item, name, options = {}, grid = {}, event_handlers = [])
|
164
|
-
|
476
|
+
if (options.delete(:root))
|
477
|
+
@native_item = TkRoot.new { title options[:title] }
|
478
|
+
else
|
479
|
+
@native_item = TkToplevel.new { title options[:title] }
|
480
|
+
end
|
165
481
|
apply_options(options)
|
166
482
|
end
|
483
|
+
|
484
|
+
def focus
|
485
|
+
self.native_item.set_focus
|
486
|
+
end
|
167
487
|
end
|
168
488
|
|
169
489
|
TK_CLASSES = {
|
@@ -174,10 +494,17 @@ module TkComponent
|
|
174
494
|
label: Tk::Tile::Label,
|
175
495
|
entry: Tk::Tile::Entry,
|
176
496
|
button: Tk::Tile::Button,
|
497
|
+
radio_set: Tk::Tile::Frame,
|
498
|
+
radio_button: Tk::Tile::RadioButton,
|
177
499
|
canvas: Tk::Canvas,
|
178
500
|
text: ::TkText,
|
179
501
|
scale: Tk::Tile::Scale,
|
180
|
-
group: Tk::Tile::LabelFrame
|
502
|
+
group: Tk::Tile::LabelFrame,
|
503
|
+
tree: Tk::Tile::Treeview,
|
504
|
+
hscroll_bar: Tk::Tile::Scrollbar,
|
505
|
+
vscroll_bar: Tk::Tile::Scrollbar,
|
506
|
+
hpaned: Tk::Tile::Paned,
|
507
|
+
vpaned: Tk::Tile::Paned
|
181
508
|
}
|
182
509
|
|
183
510
|
ITEM_CLASSES = {
|
@@ -188,10 +515,19 @@ module TkComponent
|
|
188
515
|
label: TkComponent::Builder::TkItem,
|
189
516
|
entry: TkComponent::Builder::TkEntry,
|
190
517
|
button: TkComponent::Builder::TkItem,
|
518
|
+
radio_set: TkComponent::Builder::TkRadioSet,
|
519
|
+
radio_button: TkComponent::Builder::TkRadioButton,
|
191
520
|
canvas: TkComponent::Builder::TkItem,
|
192
521
|
text: TkComponent::Builder::TkText,
|
193
522
|
scale: TkComponent::Builder::TkScale,
|
194
|
-
group: TkComponent::Builder::TkItem
|
523
|
+
group: TkComponent::Builder::TkItem,
|
524
|
+
tree: TkComponent::Builder::TkTree,
|
525
|
+
tree_node: TkComponent::Builder::TkTreeNode,
|
526
|
+
hscroll_bar: TkComponent::Builder::HScrollbar,
|
527
|
+
vscroll_bar: TkComponent::Builder::VScrollbar,
|
528
|
+
hpaned: TkComponent::Builder::HPanedWindow,
|
529
|
+
vpaned: TkComponent::Builder::VPanedWindow
|
530
|
+
|
195
531
|
}
|
196
532
|
end
|
197
533
|
end
|