vimamsa 0.1.5 → 0.1.8

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.
@@ -0,0 +1,560 @@
1
+ $idle_scroll_to_mark = false
2
+
3
+ def gui_open_file_dialog(dirpath)
4
+ dialog = Gtk::FileChooserDialog.new(:title => "Open file",
5
+ :action => :open,
6
+ :buttons => [[Gtk::Stock::OPEN, :accept],
7
+ [Gtk::Stock::CANCEL, :cancel]])
8
+ dialog.set_current_folder(dirpath)
9
+
10
+ dialog.signal_connect("response") do |dialog, response_id|
11
+ if response_id == Gtk::ResponseType::ACCEPT
12
+ open_new_file(dialog.filename)
13
+ # debug "uri = #{dialog.uri}"
14
+ end
15
+ dialog.destroy
16
+ end
17
+ dialog.run
18
+ end
19
+
20
+ def gui_file_saveas(dirpath)
21
+ dialog = Gtk::FileChooserDialog.new(:title => "Save as",
22
+ :action => :save,
23
+ :buttons => [[Gtk::Stock::SAVE, :accept],
24
+ [Gtk::Stock::CANCEL, :cancel]])
25
+ dialog.set_current_folder(dirpath)
26
+ dialog.signal_connect("response") do |dialog, response_id|
27
+ if response_id == Gtk::ResponseType::ACCEPT
28
+ file_saveas(dialog.filename)
29
+ end
30
+ dialog.destroy
31
+ end
32
+
33
+ dialog.run
34
+ end
35
+
36
+ def idle_func
37
+ # debug "IDLEFUNC"
38
+ if $idle_scroll_to_mark
39
+ # Ripl.start :binding => binding
40
+ # $view.get_visible_rect
41
+ vr = $view.visible_rect
42
+
43
+ # iter = b.get_iter_at(:offset => i)
44
+
45
+ b = $view.buffer
46
+ iter = b.get_iter_at(:offset => b.cursor_position)
47
+ iterxy = $view.get_iter_location(iter)
48
+ # debug "ITERXY" + iterxy.inspect
49
+ # Ripl.start :binding => binding
50
+
51
+ intr = iterxy.intersect(vr)
52
+ if intr.nil?
53
+ $view.set_cursor_pos($view.buffer.cursor_position)
54
+ else
55
+ $idle_scroll_to_mark = false
56
+ end
57
+
58
+ sleep(0.1)
59
+ end
60
+ sleep(0.01)
61
+ return true
62
+ end
63
+
64
+ def center_on_current_line()
65
+ b = $view.buffer
66
+ iter = b.get_iter_at(:offset => b.cursor_position)
67
+ within_margin = 0.0 #margin as a [0.0,0.5) fraction of screen size
68
+ use_align = true
69
+ xalign = 0.0 #0.0=top 1.0=bottom, 0.5=center
70
+ yalign = 0.5
71
+ $view.scroll_to_iter(iter, within_margin, use_align, xalign, yalign)
72
+ end
73
+
74
+ def get_visible_area()
75
+ view = $view
76
+ vr = view.visible_rect
77
+ startpos = view.get_iter_at_position_raw(vr.x, vr.y)[1].offset
78
+ endpos = view.get_iter_at_position_raw(vr.x + vr.width, vr.y + vr.height)[1].offset
79
+ return [startpos, endpos]
80
+ end
81
+
82
+ def page_up
83
+ $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
84
+ return true
85
+ end
86
+
87
+ def page_down
88
+ $view.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), 1, false)
89
+ return true
90
+ end
91
+
92
+ def paste_system_clipboard()
93
+ # clipboard = $vmag.window.get_clipboard(Gdk::Selection::CLIPBOARD)
94
+ utf8_string = Gdk::Atom.intern("UTF8_STRING")
95
+ # x = clipboard.request_contents(utf8_string)
96
+
97
+ widget = Gtk::Invisible.new
98
+ clipboard = Gtk::Clipboard.get_default($vmag.window.display)
99
+ received_text = ""
100
+
101
+ target_string = Gdk::Selection::TARGET_STRING
102
+ ti = clipboard.request_contents(target_string)
103
+
104
+ # clipboard.request_contents(target_string) do |_clipboard, selection_data|
105
+ # received_text = selection_data.text
106
+ # debug "received_text=#{received_text}"
107
+ # end
108
+ if clipboard.wait_is_text_available?
109
+ received_text = clipboard.wait_for_text
110
+ end
111
+
112
+ if received_text != "" and !received_text.nil?
113
+ max_clipboard_items = 100
114
+ if received_text != $clipboard[-1]
115
+ #TODO: HACK
116
+ $paste_lines = false
117
+ end
118
+ $clipboard << received_text
119
+ # debug $clipboard[-1]
120
+ $clipboard = $clipboard[-([$clipboard.size, max_clipboard_items].min)..-1]
121
+ end
122
+ return received_text
123
+ end
124
+
125
+ def set_system_clipboard(arg)
126
+ # return if arg.class != String
127
+ # return if s.size < 1
128
+ # utf8_string = Gdk::Atom.intern("UTF8_STRING")
129
+ widget = Gtk::Invisible.new
130
+ clipboard = Gtk::Clipboard.get_default($vmag.window.display)
131
+ clipboard.text = arg
132
+ end
133
+
134
+ def gui_create_buffer(id)
135
+ debug "gui_create_buffer(#{id})"
136
+ buf1 = GtkSource::Buffer.new()
137
+ view = VSourceView.new()
138
+
139
+ view.set_highlight_current_line(true)
140
+ view.set_show_line_numbers(true)
141
+ view.set_buffer(buf1)
142
+
143
+ ssm = GtkSource::StyleSchemeManager.new
144
+ ssm.set_search_path(ssm.search_path << ppath("styles/"))
145
+ # sty = ssm.get_scheme("dark")
146
+ sty = ssm.get_scheme("molokai_edit")
147
+ # debug ssm.scheme_ids
148
+
149
+ view.buffer.highlight_matching_brackets = true
150
+ view.buffer.style_scheme = sty
151
+
152
+ provider = Gtk::CssProvider.new
153
+ provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
154
+ # provider.load(data: "textview { font-family: Arial; font-size: 12pt; }")
155
+ view.style_context.add_provider(provider)
156
+ view.wrap_mode = :char
157
+ view.set_tab_width(conf(:tab_width))
158
+
159
+
160
+ $vmag.buffers[id] = view
161
+ end
162
+
163
+ def gui_set_file_lang(id, lname)
164
+ view = $vmag.buffers[id]
165
+ lm = GtkSource::LanguageManager.new
166
+ lang = nil
167
+ lm.set_search_path(lm.search_path << ppath("lang/"))
168
+ lang = lm.get_language(lname)
169
+
170
+ view.buffer.language = lang
171
+ view.buffer.highlight_syntax = true
172
+ end
173
+
174
+ def gui_add_image(imgpath, pos)
175
+ end
176
+
177
+ # TODO:?
178
+ def gui_select_window_close(arg = nil)
179
+ end
180
+
181
+ # def set_window_title(str)
182
+ # unimplemented
183
+ # end
184
+
185
+ def gui_set_buffer_contents(id, txt)
186
+ # $vbuf.set_text(txt)
187
+ debug "gui_set_buffer_contents(#{id}, txt)"
188
+
189
+ $vmag.buffers[id].buffer.set_text(txt)
190
+ end
191
+
192
+ def gui_set_cursor_pos(id, pos)
193
+ $view.set_cursor_pos(pos)
194
+ # Ripl.start :binding => binding
195
+ end
196
+
197
+ def gui_set_current_buffer(id)
198
+ view = $vmag.buffers[id]
199
+ debug "gui_set_current_buffer(#{id}), view=#{view}"
200
+ buf1 = view.buffer
201
+ $vmag.view = view
202
+ $vmag.buf1 = buf1
203
+ $view = view
204
+ $vbuf = buf1
205
+
206
+ $vmag.sw.remove($vmag.sw.child) if !$vmag.sw.child.nil?
207
+ $vmag.sw.add(view)
208
+
209
+ view.grab_focus
210
+ #view.set_focus(10)
211
+ view.set_cursor_visible(true)
212
+ #view.move_cursor(1, 1, false)
213
+ view.place_cursor_onscreen
214
+
215
+ #TODO:
216
+ # itr = view.buffer.get_iter_at(:offset => 0)
217
+ # view.buffer.place_cursor(itr)
218
+
219
+ # wtitle = ""
220
+ # wtitle = buf.fname if !buf.fname.nil?
221
+ $vmag.sw.show_all
222
+ end
223
+
224
+ def gui_set_window_title(wtitle, subtitle = "")
225
+ $vmag.window.title = wtitle
226
+ $vmag.window.titlebar.subtitle = subtitle
227
+ end
228
+
229
+ class VMAgui
230
+ attr_accessor :buffers, :sw, :view, :buf1, :window
231
+
232
+ VERSION = "1.0"
233
+
234
+ HEART = "♥"
235
+ RADIUS = 150
236
+ N_WORDS = 5
237
+ FONT = "Serif 18"
238
+ TEXT = "I ♥ GTK+"
239
+
240
+ def initialize()
241
+ @show_overlay = true
242
+ @da = nil
243
+ @buffers = {}
244
+ @view = nil
245
+ @buf1 = nil
246
+ end
247
+
248
+ def run
249
+ init_window
250
+ # init_rtext
251
+ Gtk.main
252
+ end
253
+
254
+ def start_overlay_draw()
255
+ @da = Gtk::Fixed.new
256
+ @overlay.add_overlay(@da)
257
+ @overlay.set_overlay_pass_through(@da, true)
258
+ end
259
+
260
+ def clear_overlay()
261
+ if @da != nil
262
+ @overlay.remove(@da)
263
+ end
264
+ end
265
+
266
+ def overlay_draw_text(text, textpos)
267
+ # debug "overlay_draw_text #{[x,y]}"
268
+ (x, y) = @view.pos_to_coord(textpos)
269
+ # debug "overlay_draw_text #{[x,y]}"
270
+ label = Gtk::Label.new("<span background='#00000088' foreground='#ff0000' weight='ultrabold'>#{text}</span>")
271
+ label.use_markup = true
272
+ @da.put(label, x, y)
273
+ end
274
+
275
+ def end_overlay_draw()
276
+ @da.show_all
277
+ end
278
+
279
+ def toggle_overlay
280
+ @show_overlay = @show_overlay ^ 1
281
+ if !@show_overlay
282
+ if @da != nil
283
+ @overlay.remove(@da)
284
+ end
285
+ return
286
+ else
287
+ @da = Gtk::Fixed.new
288
+ @overlay.add_overlay(@da)
289
+ @overlay.set_overlay_pass_through(@da, true)
290
+ end
291
+
292
+ (startpos, endpos) = get_visible_area
293
+ s = @view.buffer.text
294
+ wpos = s.enum_for(:scan, /\W(\w)/).map { Regexp.last_match.begin(0) + 1 }
295
+ wpos = wpos[0..130]
296
+
297
+ # vr = @view.visible_rect
298
+ # # gtk_text_view_get_line_at_y
299
+ # # gtk_text_view_get_iter_at_position
300
+ # gtk_text_view_get_iter_at_position(vr.
301
+ # istart = @view.get_iter_at_position(vr.x,vr.y)
302
+ # istart = @view.get_iter_at_y(vr.y)
303
+ # startpos = @view.get_iter_at_position_raw(vr.x,vr.y)[1].offset
304
+ # endpos = @view.get_iter_at_position_raw(vr.x+vr.width,vr.y+vr.height)[1].offset
305
+ # debug "startpos,endpos:#{[startpos, endpos]}"
306
+
307
+ da = @da
308
+ if false
309
+ da.signal_connect "draw" do |widget, cr|
310
+ cr.save
311
+ for pos in wpos
312
+ (x, y) = @view.pos_to_coord(pos)
313
+
314
+ layout = da.create_pango_layout("XY")
315
+ desc = Pango::FontDescription.new("sans bold 11")
316
+ layout.font_description = desc
317
+
318
+ cr.move_to(x, y)
319
+ # cr.move_to(gutter_width, 300)
320
+ cr.pango_layout_path(layout)
321
+
322
+ cr.set_source_rgb(1.0, 0.0, 0.0)
323
+ cr.fill_preserve
324
+ end
325
+ cr.restore
326
+ false # = draw other
327
+ # true # = Don't draw others
328
+ end
329
+ end
330
+
331
+ for pos in wpos
332
+ (x, y) = @view.pos_to_coord(pos)
333
+ # da.put(Gtk::Label.new("AB"), x, y)
334
+ label = Gtk::Label.new("<span background='#00000088' foreground='#ff0000' weight='ultrabold'>AB</span>")
335
+ label.use_markup = true
336
+ da.put(label, x, y)
337
+ end
338
+
339
+ # debug @view.pos_to_coord(300).inspect
340
+
341
+ @da.show_all
342
+ end
343
+
344
+ def handle_deltas()
345
+ while d = buf.deltas.shift
346
+ pos = d[0]
347
+ op = d[1]
348
+ num = d[2]
349
+ txt = d[3]
350
+ if op == DELETE
351
+ startiter = @buf1.get_iter_at(:offset => pos)
352
+ enditer = @buf1.get_iter_at(:offset => pos + num)
353
+ @buf1.delete(startiter, enditer)
354
+ elsif op == INSERT
355
+ startiter = @buf1.get_iter_at(:offset => pos)
356
+ @buf1.insert(startiter, txt)
357
+ end
358
+ end
359
+ end
360
+
361
+ def add_to_minibuf(msg)
362
+ startiter = @minibuf.buffer.get_iter_at(:offset => 0)
363
+ @minibuf.buffer.insert(startiter, "#{msg}\n")
364
+ @minibuf.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
365
+ end
366
+
367
+ def init_minibuffer()
368
+ # Init minibuffer
369
+ sw = Gtk::ScrolledWindow.new
370
+ sw.set_policy(:automatic, :automatic)
371
+ overlay = Gtk::Overlay.new
372
+ overlay.add(sw)
373
+ # @vpaned.pack2(overlay, :resize => false)
374
+ @vbox.attach(overlay, 0, 2, 1, 1)
375
+ # overlay.set_size_request(-1, 50)
376
+ # $ovrl = overlay
377
+ # $ovrl.set_size_request(-1, 30)
378
+ $sw2 = sw
379
+ sw.set_size_request(-1, 12)
380
+
381
+ view = VSourceView.new()
382
+ view.set_highlight_current_line(false)
383
+ view.set_show_line_numbers(false)
384
+ # view.set_buffer(buf1)
385
+ ssm = GtkSource::StyleSchemeManager.new
386
+ ssm.set_search_path(ssm.search_path << ppath("styles/"))
387
+ sty = ssm.get_scheme("molokai_edit")
388
+ view.buffer.highlight_matching_brackets = false
389
+ view.buffer.style_scheme = sty
390
+ provider = Gtk::CssProvider.new
391
+ # provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
392
+ provider.load(data: "textview { font-family: Arial; font-size: 10pt; color:#ff0000}")
393
+ view.style_context.add_provider(provider)
394
+ view.wrap_mode = :char
395
+ @minibuf = view
396
+ # Ripl.start :binding => binding
397
+ # startiter = view.buffer.get_iter_at(:offset => 0)
398
+ message("STARTUP")
399
+ sw.add(view)
400
+ end
401
+
402
+ def init_header_bar()
403
+ header = Gtk::HeaderBar.new
404
+ @header = header
405
+ header.show_close_button = true
406
+ header.title = ""
407
+ header.has_subtitle = true
408
+ header.subtitle = ""
409
+ # Ripl.start :binding => binding
410
+
411
+ # icon = Gio::ThemedIcon.new("mail-send-receive-symbolic")
412
+ # icon = Gio::ThemedIcon.new("document-open-symbolic")
413
+ # icon = Gio::ThemedIcon.new("dialog-password")
414
+
415
+ #edit-redo edit-paste edit-find-replace edit-undo edit-find edit-cut edit-copy
416
+ #document-open document-save document-save-as document-properties document-new
417
+ # document-revert-symbolic
418
+ #
419
+
420
+ #TODO:
421
+ # button = Gtk::Button.new
422
+ # icon = Gio::ThemedIcon.new("open-menu-symbolic")
423
+ # image = Gtk::Image.new(:icon => icon, :size => :button)
424
+ # button.add(image)
425
+ # header.pack_end(button)
426
+
427
+ button = Gtk::Button.new
428
+ icon = Gio::ThemedIcon.new("document-open-symbolic")
429
+ image = Gtk::Image.new(:icon => icon, :size => :button)
430
+ button.add(image)
431
+ header.pack_end(button)
432
+
433
+ button.signal_connect "clicked" do |_widget|
434
+ open_file_dialog
435
+ end
436
+
437
+ button = Gtk::Button.new
438
+ icon = Gio::ThemedIcon.new("document-save-symbolic")
439
+ image = Gtk::Image.new(:icon => icon, :size => :button)
440
+ button.add(image)
441
+ header.pack_end(button)
442
+ button.signal_connect "clicked" do |_widget|
443
+ buf.save
444
+ end
445
+
446
+ button = Gtk::Button.new
447
+ icon = Gio::ThemedIcon.new("document-new-symbolic")
448
+ image = Gtk::Image.new(:icon => icon, :size => :button)
449
+ button.add(image)
450
+ header.pack_end(button)
451
+ button.signal_connect "clicked" do |_widget|
452
+ create_new_file
453
+ end
454
+
455
+ box = Gtk::Box.new(:horizontal, 0)
456
+ box.style_context.add_class("linked")
457
+
458
+ button = Gtk::Button.new
459
+ image = Gtk::Image.new(:icon_name => "pan-start-symbolic", :size => :button)
460
+ button.add(image)
461
+ box.add(button)
462
+ button.signal_connect "clicked" do |_widget|
463
+ history_switch_backwards
464
+ end
465
+
466
+ button = Gtk::Button.new
467
+ image = Gtk::Image.new(:icon_name => "pan-end-symbolic", :size => :button)
468
+ button.add(image)
469
+ box.add(button)
470
+ button.signal_connect "clicked" do |_widget|
471
+ history_switch_forwards
472
+ end
473
+
474
+ button = Gtk::Button.new
475
+ icon = Gio::ThemedIcon.new("window-close-symbolic")
476
+ image = Gtk::Image.new(:icon => icon, :size => :button)
477
+ button.add(image)
478
+ box.add(button)
479
+ button.signal_connect "clicked" do |_widget|
480
+ bufs.close_current_buffer
481
+ end
482
+
483
+ header.pack_start(box)
484
+ @window.titlebar = header
485
+ @window.add(Gtk::TextView.new)
486
+ end
487
+
488
+ def create_menu_item(label, depth)
489
+ menuitem = Gtk::MenuItem.new(:label => label)
490
+ menuitem.submenu = create_menu(depth)
491
+ @menubar.append(menuitem)
492
+ end
493
+
494
+ def create_menu(depth)
495
+ return nil if depth < 1
496
+
497
+ menu = Gtk::Menu.new
498
+ last_item = nil
499
+ (0..5).each do |i|
500
+ j = i + 1
501
+ label = "item #{depth} - #{j}"
502
+ menu_item = Gtk::RadioMenuItem.new(nil, label)
503
+ menu_item.join_group(last_item) if last_item
504
+ last_item = menu_item
505
+ menu.append(menu_item)
506
+ menu_item.sensitive = false if i == 3
507
+ menu_item.submenu = create_menu(depth - 1)
508
+ end
509
+
510
+ menu
511
+ end
512
+
513
+ def init_window
514
+ @window = Gtk::Window.new(:toplevel)
515
+ @window.set_default_size(650, 850)
516
+ @window.title = "Multiple Views"
517
+ @window.show_all
518
+ # vpaned = Gtk::Paned.new(:horizontal)
519
+ @vpaned = Gtk::Paned.new(:vertical)
520
+ #@vpaned = Gtk::Box.new(:vertical, 0)
521
+ # @vbox = Gtk::Box.new(:vertical, 0)
522
+ @vbox = Gtk::Grid.new()
523
+ @window.add(@vbox)
524
+
525
+ @menubar = Gtk::MenuBar.new
526
+ @menubar.expand = false
527
+
528
+ @sw = Gtk::ScrolledWindow.new
529
+ @sw.set_policy(:automatic, :automatic)
530
+ @overlay = Gtk::Overlay.new
531
+ @overlay.add(@sw)
532
+
533
+ # @vpaned.pack1(@overlay, :resize => true)
534
+ # @vpaned.pack2(@menubar, :resize => false)
535
+ # @vbox.add(@menubar, :resize => false)
536
+
537
+ init_header_bar
538
+
539
+ # @window.show_all
540
+
541
+ # @vbox.pack_start(@menubar, :expand => false, :fill => false, :padding => 0 )
542
+ # @vbox.pack_start(@menubar)
543
+ # @vbox.pack_start(@overlay, :expand => true, :fill => true, :padding => 0 )
544
+ # @vbox.pack_start(@overlay, :expand => true, :fill => true, :padding => 0 )
545
+ @vbox.attach(@menubar, 0, 0, 1, 1)
546
+ @vbox.attach(@overlay, 0, 1, 1, 1)
547
+ @overlay.vexpand = true
548
+ @overlay.hexpand = true
549
+
550
+ @menubar.vexpand = false
551
+ @menubar.hexpand = false
552
+
553
+ init_minibuffer
554
+
555
+ @window.show_all
556
+ vma.start
557
+ Vimamsa::Menu.new(@menubar)
558
+ @window.show_all
559
+ end
560
+ end
@@ -0,0 +1,110 @@
1
+ module Vimamsa
2
+ class Menu
3
+ def add_to_menu(_mpath, x)
4
+ mpath = _mpath.split(".")
5
+ curnfo = @nfo
6
+ for y in mpath
7
+ debug(curnfo.inspect)
8
+ if y.equal?(mpath.last)
9
+ curnfo[y] = x
10
+ elsif curnfo[y].nil?
11
+ curnfo[y] = { :label => y, :items => {} }
12
+ end
13
+ curnfo[y][:items] = {} if curnfo[y][:items].class != Hash
14
+ curnfo = curnfo[y][:items]
15
+ end #end for
16
+ end
17
+
18
+ def add_menu_items()
19
+
20
+ add_to_menu "File.Example", { :label => "<span foreground='#888888'>Action, [mode] key binding</span>", :action => nil }
21
+ add_to_menu "File.Save", { :label => "Save", :action => :buf_save }
22
+ add_to_menu "File.Save as", { :label => "Save As...", :action => :buf_save_as }
23
+ add_to_menu "File.Open", { :label => "Open", :action => :open_file_dialog }
24
+
25
+ add_to_menu "File.New", { :label => "New file", :action => :buf_new }
26
+ add_to_menu "File.Revert", { :label => "Reload file from disk", :action => :buf_revert }
27
+ add_to_menu "File.List", { :label => "List open files", :action => :start_buf_manager }
28
+
29
+ add_to_menu "File.Quit", { :label => "Quit", :action => :quit }
30
+
31
+ add_to_menu "Edit.Undo", { :label => "Undo edit", :action => :edit_undo }
32
+ add_to_menu "Edit.Redo", { :label => "Redo edit", :action => :edit_redo }
33
+ add_to_menu "Edit.SearchReplace", { :label => "Search and replace", :action => :gui_search_replace }
34
+ add_to_menu "Edit.Find", { :label => "Find", :action => :find_in_buffer }
35
+
36
+ add_to_menu "Actions.SearchForActions", { :label => "Search for Actions", :action => :search_actions }
37
+
38
+ add_to_menu "Actions.Grep", { :label => "Grep lines", :action => :invoke_grep_search }
39
+
40
+ add_to_menu "Actions.FileHistoryFinder", { :label => "Search files in history", :action => :gui_file_history_finder }
41
+
42
+ add_to_menu "Actions.experimental.Diff", { :label => "Show Diff of\nunsaved changes", :action => :diff_buffer }
43
+
44
+ add_to_menu "Actions.experimental.EnableDebug", { :label => "Enable debug", :action => :enable_debug }
45
+ add_to_menu "Actions.experimental.DisableDebug", { :label => "Disable debug", :action => :disable_debug }
46
+ add_to_menu "Actions.experimental.ShowImages", { :label => "Show images ⟦img:path⟧", :action => :show_images }
47
+
48
+
49
+ add_to_menu "Actions.EncryptFile", { :label => "Encrypt file", :action => :encrypt_file }
50
+ add_to_menu "Help.KeyBindings", { :label => "Show key bindings", :action => :show_key_bindings }
51
+
52
+
53
+ #TODO: :auto_indent_buffer
54
+
55
+ # add_to_menu "Actions.Ack", { :label => "source code search (Ack)", :action => :ack_search }
56
+
57
+ end
58
+
59
+ def initialize(menubar)
60
+ # nfo["file"] = { :items => {}, :label => "File" }
61
+ # nfo["actions"] = { :items => {}, :label => "Actions" }
62
+ # nfo["help"] = { :items => {}, :label => "Help" }
63
+
64
+ @nfo = {}
65
+
66
+ add_menu_items
67
+
68
+ # add_to_menu("help.extra.keybindings", { :label => "Show keybindings" })
69
+ # add_to_menu("help.extra.nfo.keybindings", { :label => "Show keybindings" })
70
+ # add_to_menu("help.keybindings", { :label => "Show keybindings <span foreground='#888888' >C ? k</span>" }) #font='12' weight='ultrabold'
71
+
72
+ for k, v in @nfo
73
+ build_menu(v, menubar)
74
+ end
75
+ end
76
+
77
+ def build_menu(nfo, parent)
78
+ menu = Gtk::Menu.new
79
+ if nfo[:action]
80
+ kbd_str = ""
81
+ for mode_str in ["C", "V"]
82
+ c_kbd = vma.kbd.act_bindings[mode_str][nfo[:action]]
83
+ if c_kbd.class == String
84
+ kbd_str = " <span foreground='#888888'><span weight='bold'>[#{mode_str}]</span> #{c_kbd}</span>"
85
+ break
86
+ end
87
+ end
88
+
89
+ label_str = nfo[:label] + kbd_str
90
+ menuitem = Gtk::MenuItem.new(:label => label_str)
91
+ menuitem.children[0].set_markup(label_str)
92
+
93
+ menuitem.signal_connect("activate") do
94
+ call_action(nfo[:action])
95
+ end
96
+ else
97
+ menuitem = Gtk::MenuItem.new(:label => nfo[:label])
98
+ menuitem.children[0].set_markup(nfo[:label])
99
+ end
100
+
101
+ if !nfo[:items].nil? and !nfo[:items].empty?
102
+ for k2, item in nfo[:items]
103
+ build_menu(item, menu)
104
+ end
105
+ menuitem.submenu = menu
106
+ end
107
+ parent.append(menuitem)
108
+ end
109
+ end #end class
110
+ end