GtkSimpleLayout 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +339 -0
- data/README +47 -0
- data/Rakefile +18 -0
- data/example/auto_event_map.rb +60 -0
- data/example/basic.rb +36 -0
- data/example/calculator.rb +64 -0
- data/example/composit_layout.rb +26 -0
- data/example/expose_components.rb +35 -0
- data/example/group.rb +70 -0
- data/example/hello_world.rb +23 -0
- data/example/menu.rb +54 -0
- data/example/serial_port_setup.rb +85 -0
- data/example/with_attr.rb +44 -0
- data/lib/simple_layout.rb +488 -0
- metadata +78 -0
@@ -0,0 +1,488 @@
|
|
1
|
+
require 'gtk2'
|
2
|
+
|
3
|
+
module SimpleLayout
|
4
|
+
|
5
|
+
class LayoutError < Exception; end
|
6
|
+
|
7
|
+
class EventHandlerProxy
|
8
|
+
def initialize(host, evt, &block)
|
9
|
+
@host = host
|
10
|
+
@evt = evt
|
11
|
+
self << block if block
|
12
|
+
end
|
13
|
+
def <<(v)
|
14
|
+
if v && v.respond_to?('call')
|
15
|
+
@host.signal_connect(@evt) do |*args|
|
16
|
+
v.call(*args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ExtClassMethod
|
24
|
+
def inspector_opt(opt = nil)
|
25
|
+
@insp_opt ||= {
|
26
|
+
:enable => (ENV['INSPECTOR_ENABLE'] == '1'),
|
27
|
+
:border_width => (ENV['INSPECTOR_BORDER_WIDTH'] || 5)
|
28
|
+
}
|
29
|
+
@insp_opt.merge! opt if opt
|
30
|
+
@insp_opt
|
31
|
+
end
|
32
|
+
|
33
|
+
def layout_class_maps
|
34
|
+
@layout_class_maps_hash ||= {
|
35
|
+
'image' => Gtk::Image,
|
36
|
+
'label' => Gtk::Label,
|
37
|
+
'progress_bar' => Gtk::ProgressBar,
|
38
|
+
'status_bar' => Gtk::Statusbar,
|
39
|
+
'button' => Gtk::Button,
|
40
|
+
'check_button' => Gtk::CheckButton,
|
41
|
+
'radio_button' => Gtk::RadioButton,
|
42
|
+
'toggle_button' => Gtk::ToggleButton,
|
43
|
+
'link_button' => Gtk::LinkButton,
|
44
|
+
'entry' => Gtk::Entry,
|
45
|
+
'hscale' => Gtk::HScale,
|
46
|
+
'vscale' => Gtk::VScale,
|
47
|
+
'spin_button' => Gtk::SpinButton,
|
48
|
+
'text_view' => Gtk::TextView,
|
49
|
+
'tree_view' => Gtk::TreeView,
|
50
|
+
'cell_view' => Gtk::CellView,
|
51
|
+
'icon_view' => Gtk::IconView,
|
52
|
+
'combobox' => Gtk::ComboBox,
|
53
|
+
'combobox_entry' => Gtk::ComboBoxEntry,
|
54
|
+
#'menu' => Gtk::Menu,
|
55
|
+
#'menubar' => Gtk::MenuBar,
|
56
|
+
'toolbar' => Gtk::Toolbar,
|
57
|
+
'toolitem' => Gtk::ToolItem,
|
58
|
+
'separator_toolitem' => Gtk::SeparatorToolItem,
|
59
|
+
'tool_button' => Gtk::ToolButton,
|
60
|
+
'toggle_tool_button' => Gtk::ToggleToolButton,
|
61
|
+
'radio_tool_button' => Gtk::RadioToolButton,
|
62
|
+
'color_button' => Gtk::ColorButton,
|
63
|
+
'color_selection' => Gtk::ColorSelection,
|
64
|
+
'file_chooser_button' => Gtk::FileChooserButton,
|
65
|
+
'file_chooser_widget' => Gtk::FileChooserWidget,
|
66
|
+
'font_button' => Gtk::FontButton,
|
67
|
+
'font_selection' => Gtk::FontSelection,
|
68
|
+
'alignment' => Gtk::Alignment,
|
69
|
+
'aspect_frame' => Gtk::AspectFrame,
|
70
|
+
'hbox' => Gtk::HBox,
|
71
|
+
'vbox' => Gtk::VBox,
|
72
|
+
'hbutton_box' => Gtk::HButtonBox,
|
73
|
+
'vbutton_box' => Gtk::VButtonBox,
|
74
|
+
'hpaned' => Gtk::HPaned,
|
75
|
+
'vpaned' => Gtk::VPaned,
|
76
|
+
'layout' => Gtk::Layout,
|
77
|
+
'notebook' => Gtk::Notebook,
|
78
|
+
'table' => Gtk::Table,
|
79
|
+
'expander' => Gtk::Expander,
|
80
|
+
'frame' => Gtk::Frame,
|
81
|
+
'hseparator' => Gtk::HSeparator,
|
82
|
+
'vseparator' => Gtk::VSeparator,
|
83
|
+
'hscrollbar' => Gtk::HScrollbar,
|
84
|
+
'vscrollbar' => Gtk::VScrollbar,
|
85
|
+
'scrolled_window' => Gtk::ScrolledWindow,
|
86
|
+
'arrow' => Gtk::Arrow,
|
87
|
+
'calendar' => Gtk::Calendar,
|
88
|
+
'drawing_area' => Gtk::DrawingArea,
|
89
|
+
'event_box' => Gtk::EventBox,
|
90
|
+
'handle_box' => Gtk::HandleBox,
|
91
|
+
'viewport' => Gtk::Viewport,
|
92
|
+
'curve' => Gtk::Curve,
|
93
|
+
'gamma_curve' => Gtk::GammaCurve,
|
94
|
+
'hruler' => Gtk::HRuler,
|
95
|
+
'vruler' => Gtk::VRuler,
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
module Base
|
102
|
+
def Base.included(base)
|
103
|
+
base.extend(ExtClassMethod)
|
104
|
+
base.layout_class_maps.each do |k, v|
|
105
|
+
define_method(k) do |*args, &block|
|
106
|
+
create_component(v, args, block)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
public
|
112
|
+
|
113
|
+
# register automatic event handlers
|
114
|
+
def register_auto_events()
|
115
|
+
self.methods.each do |name|
|
116
|
+
if name =~ /^(.+)_on_(.+)$/
|
117
|
+
w, evt = $1, $2
|
118
|
+
w = component(w.to_sym)
|
119
|
+
w.signal_connect(evt) do |*args| self.send(name, *args) end if w
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# expose the components as instance variables
|
125
|
+
def expose_components()
|
126
|
+
@components.each_key do |k|
|
127
|
+
unless self.respond_to?(k.to_s, true)
|
128
|
+
self.instance_eval("def #{k.to_s}; component(:#{k.to_s}) end")
|
129
|
+
else
|
130
|
+
raise LayoutError, "#{k} is conflit with method, please redifine component id"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# add a widget to container (and/or become a new container as well).
|
136
|
+
# do not call this function directly unless knowing what you are doing
|
137
|
+
def add_component(w, container, layout_opt = nil)
|
138
|
+
if @pass_on_stack.last.nil? || @pass_on_stack.last[0] == false
|
139
|
+
if container.is_a?(Gtk::Box)
|
140
|
+
layout_opt ||= [false, false, 0]
|
141
|
+
pack_method = 'pack_start'
|
142
|
+
if layout_opt.first.is_a?(Symbol)
|
143
|
+
pack_method = 'pack_end' if layout_opt.shift == :end
|
144
|
+
end
|
145
|
+
container.send(pack_method, w, *layout_opt)
|
146
|
+
elsif container.is_a?(Gtk::Fixed) || container.is_a?(Gtk::Layout)
|
147
|
+
layout_opt ||= [0, 0]
|
148
|
+
container.put w, *layout_opt
|
149
|
+
elsif container.is_a?(Gtk::MenuShell)
|
150
|
+
container.append w
|
151
|
+
elsif container.is_a?(Gtk::Toolbar)
|
152
|
+
container.insert(container.n_items, w)
|
153
|
+
elsif container.is_a?(Gtk::MenuToolButton)
|
154
|
+
container.menu = w
|
155
|
+
elsif container.is_a?(Gtk::Table)
|
156
|
+
# should use #grid or #grid_flx to add a child to Table
|
157
|
+
elsif container.is_a?(Gtk::Notebook)
|
158
|
+
# should use #page to add a child to Notebook
|
159
|
+
elsif container.is_a?(Gtk::Paned)
|
160
|
+
# should use #area_first or #area_second to add child to Paned
|
161
|
+
elsif container.is_a?(Gtk::Container)
|
162
|
+
layout_opt ||= []
|
163
|
+
container.add(w, *layout_opt)
|
164
|
+
end
|
165
|
+
else
|
166
|
+
fun_name, args = *(@pass_on_stack.last[1])
|
167
|
+
container.send(fun_name, w, *args)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# create a "with block" for setup common attributes
|
172
|
+
def with_attr(options = {}, &block)
|
173
|
+
if block
|
174
|
+
@common_attribute ||= []
|
175
|
+
@common_attribute.push options
|
176
|
+
cnt, _ = @containers.last
|
177
|
+
block.call(cnt)
|
178
|
+
@common_attribute.pop
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# get component with given name
|
183
|
+
def component(name)
|
184
|
+
@components[name]
|
185
|
+
end
|
186
|
+
|
187
|
+
# return children array of a component or group
|
188
|
+
def component_children(name)
|
189
|
+
@component_children ||= {}
|
190
|
+
@component_children[name]
|
191
|
+
end
|
192
|
+
|
193
|
+
# group the children
|
194
|
+
def group(name)
|
195
|
+
cnt, misc = @containers.last
|
196
|
+
gs = (name ? [name].flatten : [])
|
197
|
+
gs.each{|g| @component_children[g] ||= [] }
|
198
|
+
m = { :groups => gs,
|
199
|
+
:virtual => true,
|
200
|
+
:sibling => misc[:sibling],
|
201
|
+
:insp => misc[:insp],
|
202
|
+
:layout => misc[:layout],
|
203
|
+
:options => misc[:options],
|
204
|
+
:name => nil,
|
205
|
+
}
|
206
|
+
@containers.push [cnt, m]
|
207
|
+
yield cnt if block_given?
|
208
|
+
@containers.pop
|
209
|
+
end
|
210
|
+
|
211
|
+
# for HPaned and VPaned container
|
212
|
+
def area_first(resize = true, shrink = true, &block)
|
213
|
+
container_pass_on(Gtk::Paned, 'pack1', resize, shrink, block)
|
214
|
+
end
|
215
|
+
def area_second(resize = true, shrink = true, &block)
|
216
|
+
container_pass_on(Gtk::Paned, 'pack2', resize, shrink, block)
|
217
|
+
end
|
218
|
+
|
219
|
+
# for Notebook container
|
220
|
+
def page(text = nil, &block)
|
221
|
+
container_pass_on(Gtk::Notebook, 'append_page', Gtk::Label.new(text), block)
|
222
|
+
end
|
223
|
+
|
224
|
+
# for Table container
|
225
|
+
def grid_flx(left, right, top, bottom, *args, &block)
|
226
|
+
args.push block
|
227
|
+
container_pass_on(Gtk::Table, 'attach', left, right, top, bottom, *args)
|
228
|
+
end
|
229
|
+
def grid(left, top, *args, &block)
|
230
|
+
args.push block
|
231
|
+
container_pass_on(Gtk::Table, 'attach', left, left + 1, top, top + 1, *args)
|
232
|
+
end
|
233
|
+
|
234
|
+
# menu stuff
|
235
|
+
def factory_menu_bar(name, options = {}, &block)
|
236
|
+
cb = Proc.new do |id, w|
|
237
|
+
id = id.gsub('_', '') if id.is_a?(String)
|
238
|
+
m = "menu_#{name}_on_active"
|
239
|
+
self.send(m, id, Gtk::ItemFactory.path_from_widget(w), w) if self.respond_to?(m)
|
240
|
+
end
|
241
|
+
@item_factory_stack ||= []
|
242
|
+
@item_factory_stack.push [cb, [], []]
|
243
|
+
block.call(name) if block
|
244
|
+
options[:id] ||= name.to_sym
|
245
|
+
_, _, items = @item_factory_stack.pop
|
246
|
+
accel_group = Gtk::AccelGroup.new
|
247
|
+
add_accel_group(accel_group)
|
248
|
+
fact = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU_BAR, "<#{name}>", accel_group)
|
249
|
+
fact.create_items(items)
|
250
|
+
|
251
|
+
# process item attributes
|
252
|
+
items.each do |x|
|
253
|
+
# TODO: ...
|
254
|
+
end
|
255
|
+
layout_component(fact.get_widget("<#{name}>"), options)
|
256
|
+
end
|
257
|
+
|
258
|
+
def factory_menu_item(name, options = {}, &block)
|
259
|
+
cb, stack, items = @item_factory_stack.last
|
260
|
+
branch = false
|
261
|
+
options[:type] ||= :Item
|
262
|
+
case name
|
263
|
+
when /^[-]+$/
|
264
|
+
options[:type] = :Separator
|
265
|
+
when /^<[-]+>$/
|
266
|
+
options[:type] = :Tearoff
|
267
|
+
when /^>>(.+)>>$/
|
268
|
+
name = $1
|
269
|
+
branch = true
|
270
|
+
options[:type] = :LastBranch
|
271
|
+
when /^<(.+)>$/
|
272
|
+
name = $1
|
273
|
+
branch = true
|
274
|
+
options[:type] = :Branch
|
275
|
+
end
|
276
|
+
|
277
|
+
image = options.delete(:image)
|
278
|
+
if image.is_a?(String)
|
279
|
+
options[:type] = :ImageItem
|
280
|
+
image = Gdk::Pixbuf.new(image)
|
281
|
+
elsif image.is_a?(Gdk::Pixbuf)
|
282
|
+
options[:type] = :ImageItem
|
283
|
+
elsif image
|
284
|
+
options[:type] = :StockItem
|
285
|
+
end
|
286
|
+
|
287
|
+
item = [ "#{stack.last}/#{name}",
|
288
|
+
"<#{options[:type].to_s}>",
|
289
|
+
options[:accel],
|
290
|
+
image,
|
291
|
+
cb,
|
292
|
+
options[:id] || name
|
293
|
+
]
|
294
|
+
items << item
|
295
|
+
if branch
|
296
|
+
stack.push "#{stack.last}/#{name}"
|
297
|
+
block.call(name) if block
|
298
|
+
stack.pop if branch
|
299
|
+
end
|
300
|
+
item
|
301
|
+
end
|
302
|
+
|
303
|
+
# layout the new UI component (container or widget)
|
304
|
+
def layout_component(w, options = {}, &block)
|
305
|
+
@containers ||= []
|
306
|
+
@pass_on_stack ||= []
|
307
|
+
@components ||= {}
|
308
|
+
@common_attribute ||= []
|
309
|
+
@component_children ||= {}
|
310
|
+
|
311
|
+
add_singleton_event_map(w) # so that you can use: w.on_clicked{|*args| ... }
|
312
|
+
|
313
|
+
name = options.delete(:id)
|
314
|
+
group_name = options.delete(:gid) || name
|
315
|
+
layout_opt = options.delete(:layout)
|
316
|
+
keep_top_cnt = options.delete(:keep_top_container)
|
317
|
+
|
318
|
+
options.each do |k, v|
|
319
|
+
if v.is_a?(Array)
|
320
|
+
w.send(k.to_s, *v) if w.respond_to?(k.to_s)
|
321
|
+
else
|
322
|
+
w.send(k.to_s + '=', v) if w.respond_to?(k.to_s + '=')
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
@components[name] = w if name
|
327
|
+
gs = (group_name ? [group_name].flatten : [])
|
328
|
+
gs.each{|g| @component_children[g] ||= [] }
|
329
|
+
|
330
|
+
misc = nil
|
331
|
+
if @containers.size > 0
|
332
|
+
container, misc = @containers.last
|
333
|
+
misc[:groups].each{ |g| @component_children[g].push w }
|
334
|
+
misc[:sibling] += 1
|
335
|
+
end
|
336
|
+
|
337
|
+
unless container and container.is_a? Gtk::ScrolledWindow
|
338
|
+
insp_evb = make_inspect_evb(misc, w, name, layout_opt, options)
|
339
|
+
end
|
340
|
+
|
341
|
+
if block # if given block, it's a container as well
|
342
|
+
m = { :groups => gs,
|
343
|
+
:sibling => 0,
|
344
|
+
:insp => insp_evb,
|
345
|
+
:name => name,
|
346
|
+
:layout => layout_opt,
|
347
|
+
:options => options,
|
348
|
+
}
|
349
|
+
@containers.push [w, m]
|
350
|
+
@pass_on_stack.push [false, nil]
|
351
|
+
@common_attribute.push({})
|
352
|
+
block.call(w) if block
|
353
|
+
@common_attribute.pop
|
354
|
+
@pass_on_stack.pop
|
355
|
+
@containers.pop
|
356
|
+
end
|
357
|
+
|
358
|
+
if @containers.size > 0
|
359
|
+
add_component(insp_evb || w, container, layout_opt) # add myself to parent
|
360
|
+
else
|
361
|
+
add_component(insp_evb || w, self, layout_opt) unless keep_top_cnt # add top container to host
|
362
|
+
@components[:self] = self # add host as ':self'
|
363
|
+
end
|
364
|
+
w
|
365
|
+
end
|
366
|
+
|
367
|
+
private
|
368
|
+
|
369
|
+
def add_singleton_event_map(w)
|
370
|
+
class << w
|
371
|
+
alias_method :simple_layout_singleton_method_missing, :method_missing
|
372
|
+
def method_missing(sym, *args, &block)
|
373
|
+
if sym.to_s =~ /^on_([^=]+)(=*)$/
|
374
|
+
block ||= args.last
|
375
|
+
return EventHandlerProxy.new(self, $1, &block)
|
376
|
+
else
|
377
|
+
simple_layout_singleton_method_missing(sym, *args, &block)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
# create the inspector eventbox for widget
|
384
|
+
def make_inspect_evb(cnt_misc, w, name, layout_opt, options)
|
385
|
+
insp_evb = nil
|
386
|
+
insp_opt = self.class.inspector_opt
|
387
|
+
if insp_opt[:enable]
|
388
|
+
rgb = 0xffff - @containers.size * 0x1000
|
389
|
+
insp_evb = evb = Gtk::EventBox.new
|
390
|
+
sub_evb = Gtk::EventBox.new
|
391
|
+
sub_evb.add w
|
392
|
+
evb.add sub_evb
|
393
|
+
sub_evb.border_width = insp_opt[:border_width]
|
394
|
+
evb.modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(rgb, rgb, rgb)
|
395
|
+
evbs = []
|
396
|
+
tips = ""
|
397
|
+
@containers.size.times do |i|
|
398
|
+
cnt, m = @containers[i]
|
399
|
+
if m[:insp] && (not m[:virtual])
|
400
|
+
evbs << m[:insp]
|
401
|
+
tips << "<b>container[#{i}]: #{cnt.class}#{m[:name] ? " (#{m[:name]})" : ''}</b>\n"
|
402
|
+
tips << " layout: #{m[:layout].inspect}\n" if m[:layout]
|
403
|
+
tips << " options: #{m[:options].inspect}\n" if m[:options] && m[:options].size > 0
|
404
|
+
tips << " groups: #{m[:groups].inspect}\n" if m[:groups].size > 0
|
405
|
+
end
|
406
|
+
end
|
407
|
+
evbs << evb
|
408
|
+
tips << "<b>widget: #{w.class}#{name ? " (#{name})" : ''}</b>\n"
|
409
|
+
tips << " layout: #{layout_opt.inspect}\n" if layout_opt
|
410
|
+
tips << " options: #{options.inspect}\n" if options && options.size > 0
|
411
|
+
tips << " groups: #{cnt_misc[:groups].inspect}\n" if cnt_misc && cnt_misc[:groups].size > 0
|
412
|
+
|
413
|
+
evb.signal_connect('event') do |b, evt|
|
414
|
+
b.tooltip_markup = tips
|
415
|
+
case evt.event_type
|
416
|
+
when Gdk::Event::ENTER_NOTIFY, Gdk::Event::LEAVE_NOTIFY
|
417
|
+
evbs.size.times do |i|
|
418
|
+
rgb = 0xffff - i * 0x1000
|
419
|
+
if evt.event_type == Gdk::Event::ENTER_NOTIFY
|
420
|
+
evbs[i].modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(rgb, rgb - 0x2000, rgb - 0x2000)
|
421
|
+
elsif evt.event_type == Gdk::Event::LEAVE_NOTIFY
|
422
|
+
evbs[i].modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(rgb, rgb, rgb)
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
insp_evb
|
429
|
+
end
|
430
|
+
|
431
|
+
# create a new UI component (container or widget)
|
432
|
+
def create_component(component_class, args, block)
|
433
|
+
@common_attribute ||= []
|
434
|
+
options = {}
|
435
|
+
options = args.pop if args.last.is_a?(Hash)
|
436
|
+
options.merge! @common_attribute.last if @common_attribute.last
|
437
|
+
|
438
|
+
w = component_class.new(*args)
|
439
|
+
layout_component(w, options, &block)
|
440
|
+
end
|
441
|
+
|
442
|
+
def container_pass_on(container_class, fun_name, *args)
|
443
|
+
block = args.pop # the last arg is Proc or nil
|
444
|
+
cnt, _ = @containers.last
|
445
|
+
if cnt.is_a?(container_class)
|
446
|
+
@pass_on_stack.push [true, [fun_name, args]]
|
447
|
+
block.call(cnt) if block
|
448
|
+
@pass_on_stack.pop
|
449
|
+
else
|
450
|
+
raise LayoutError, "class #{container_class} expected"
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
alias_method :simple_layout_method_missing_alias, :method_missing
|
455
|
+
|
456
|
+
def method_missing(sym, *args, &block)
|
457
|
+
if sym.to_s =~ /^(.+)_in_(.+)$/
|
458
|
+
maps = self.class.layout_class_maps
|
459
|
+
inner, outter = $1, $2
|
460
|
+
if maps[inner] && maps[outter]
|
461
|
+
if args.last.is_a?(Hash)
|
462
|
+
options = {}
|
463
|
+
options = args.pop if args.last.is_a?(Hash)
|
464
|
+
|
465
|
+
# default args pass to inner component, execpt:
|
466
|
+
# :layout pass to outter :layout
|
467
|
+
# :inner_layout pass to inner :layout
|
468
|
+
# :outter_args pass to outter args
|
469
|
+
outter_args, outter_layout_opt, options[:layout] =
|
470
|
+
options.delete(:outter_args), options.delete(:layout), options.delete(:inner_layout)
|
471
|
+
|
472
|
+
outter_args = (outter_args ? [outter_args] : []) unless outter_args.is_a?(Array)
|
473
|
+
outter_args << {} unless outter_args.last.is_a?(Hash)
|
474
|
+
outter_args.last[:layout] ||= outter_layout_opt
|
475
|
+
args.push options # push back inner options
|
476
|
+
end
|
477
|
+
|
478
|
+
inner_proc = Proc.new do
|
479
|
+
create_component(maps[inner], args, block)
|
480
|
+
end
|
481
|
+
return create_component(maps[outter], outter_args || [], inner_proc)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
simple_layout_method_missing_alias(sym, *args, &block)
|
485
|
+
end
|
486
|
+
|
487
|
+
end
|
488
|
+
end
|