vimamsa 0.1.10 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -3
- data/custom_example.rb +11 -1
- data/demo.txt +2 -2
- data/exe/vimamsa +1 -4
- data/lib/vimamsa/ack.rb +57 -9
- data/lib/vimamsa/actions.rb +1 -1
- data/lib/vimamsa/buffer.rb +270 -45
- data/lib/vimamsa/buffer_list.rb +57 -16
- data/lib/vimamsa/buffer_manager.rb +21 -4
- data/lib/vimamsa/conf.rb +10 -1
- data/lib/vimamsa/debug.rb +7 -3
- data/lib/vimamsa/easy_jump.rb +10 -6
- data/lib/vimamsa/editor.rb +57 -43
- data/lib/vimamsa/file_finder.rb +69 -71
- data/lib/vimamsa/file_history.rb +2 -3
- data/lib/vimamsa/file_manager.rb +1 -1
- data/lib/vimamsa/form_generator.rb +122 -0
- data/lib/vimamsa/gui.rb +518 -180
- data/lib/vimamsa/gui_image.rb +12 -6
- data/lib/vimamsa/gui_menu.rb +29 -20
- data/lib/vimamsa/gui_select_window.rb +40 -21
- data/lib/vimamsa/gui_sourceview.rb +264 -86
- data/lib/vimamsa/hyper_plain_text.rb +34 -1
- data/lib/vimamsa/key_actions.rb +13 -1
- data/lib/vimamsa/key_binding_tree.rb +26 -14
- data/lib/vimamsa/key_bindings_vimlike.rb +56 -26
- data/lib/vimamsa/langservp.rb +172 -0
- data/lib/vimamsa/macro.rb +9 -8
- data/lib/vimamsa/main.rb +0 -1
- data/lib/vimamsa/rbvma.rb +7 -4
- data/lib/vimamsa/search.rb +2 -1
- data/lib/vimamsa/search_replace.rb +36 -106
- data/lib/vimamsa/util.rb +55 -1
- data/lib/vimamsa/version.rb +1 -1
- data/lib/vimamsa.rb +1 -6
- data/styles/molokai_edit.xml +3 -0
- data/vimamsa.gemspec +10 -10
- metadata +24 -22
data/lib/vimamsa/gui.rb
CHANGED
@@ -3,40 +3,42 @@ $idle_scroll_to_mark = false
|
|
3
3
|
def gui_open_file_dialog(dirpath)
|
4
4
|
dialog = Gtk::FileChooserDialog.new(:title => "Open file",
|
5
5
|
:action => :open,
|
6
|
-
:buttons => [[
|
7
|
-
[
|
8
|
-
dialog.set_current_folder(dirpath)
|
6
|
+
:buttons => [["Open", :accept],
|
7
|
+
["Cancel", :cancel]])
|
8
|
+
dialog.set_current_folder(Gio::File.new_for_path(dirpath))
|
9
|
+
# dialog.set_current_folder(Gio::File.new_for_path("/tmp"))
|
9
10
|
|
10
11
|
dialog.signal_connect("response") do |dialog, response_id|
|
11
12
|
if response_id == Gtk::ResponseType::ACCEPT
|
12
|
-
open_new_file(dialog.
|
13
|
-
# debug "uri = #{dialog.uri}"
|
13
|
+
open_new_file(dialog.file.parse_name)
|
14
14
|
end
|
15
15
|
dialog.destroy
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
|
+
dialog.modal = true
|
19
|
+
dialog.show
|
18
20
|
end
|
19
21
|
|
20
22
|
def gui_file_saveas(dirpath)
|
21
23
|
dialog = Gtk::FileChooserDialog.new(:title => "Save as",
|
22
24
|
:action => :save,
|
23
|
-
:buttons => [[
|
24
|
-
[
|
25
|
-
dialog.set_current_folder(dirpath)
|
25
|
+
:buttons => [["Save", :accept],
|
26
|
+
["Cancel", :cancel]])
|
27
|
+
# dialog.set_current_folder(dirpath) #TODO:gtk4
|
26
28
|
dialog.signal_connect("response") do |dialog, response_id|
|
27
29
|
if response_id == Gtk::ResponseType::ACCEPT
|
28
|
-
file_saveas(dialog.
|
30
|
+
file_saveas(dialog.file.parse_name)
|
29
31
|
end
|
30
32
|
dialog.destroy
|
31
33
|
end
|
32
34
|
|
33
|
-
dialog.
|
35
|
+
dialog.modal = true
|
36
|
+
dialog.show
|
34
37
|
end
|
35
38
|
|
36
39
|
def idle_func
|
37
40
|
# debug "IDLEFUNC"
|
38
41
|
if $idle_scroll_to_mark
|
39
|
-
# Ripl.start :binding => binding
|
40
42
|
# $view.get_visible_rect
|
41
43
|
vr = $view.visible_rect
|
42
44
|
|
@@ -46,7 +48,6 @@ def idle_func
|
|
46
48
|
iter = b.get_iter_at(:offset => b.cursor_position)
|
47
49
|
iterxy = $view.get_iter_location(iter)
|
48
50
|
# debug "ITERXY" + iterxy.inspect
|
49
|
-
# Ripl.start :binding => binding
|
50
51
|
|
51
52
|
intr = iterxy.intersect(vr)
|
52
53
|
if intr.nil?
|
@@ -90,21 +91,16 @@ def page_down
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def paste_system_clipboard()
|
93
|
-
|
94
|
+
|
95
|
+
#TODO: Check if something useful in this old GTK3 code.
|
94
96
|
utf8_string = Gdk::Atom.intern("UTF8_STRING")
|
95
|
-
# x = clipboard.request_contents(utf8_string)
|
96
97
|
|
97
|
-
widget = Gtk::Invisible.new
|
98
98
|
clipboard = Gtk::Clipboard.get_default($vmag.window.display)
|
99
99
|
received_text = ""
|
100
100
|
|
101
101
|
target_string = Gdk::Selection::TARGET_STRING
|
102
102
|
ti = clipboard.request_contents(target_string)
|
103
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
104
|
if clipboard.wait_is_text_available?
|
109
105
|
received_text = clipboard.wait_for_text
|
110
106
|
end
|
@@ -123,12 +119,7 @@ def paste_system_clipboard()
|
|
123
119
|
end
|
124
120
|
|
125
121
|
def set_system_clipboard(arg)
|
126
|
-
|
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
|
122
|
+
vma.gui.window.display.clipboard.set(arg)
|
132
123
|
end
|
133
124
|
|
134
125
|
def gui_create_buffer(id, bufo)
|
@@ -136,6 +127,9 @@ def gui_create_buffer(id, bufo)
|
|
136
127
|
buf1 = GtkSource::Buffer.new()
|
137
128
|
view = VSourceView.new(nil, bufo)
|
138
129
|
|
130
|
+
view.register_signals()
|
131
|
+
$debug = true
|
132
|
+
|
139
133
|
ssm = GtkSource::StyleSchemeManager.new
|
140
134
|
ssm.set_search_path(ssm.search_path << ppath("styles/"))
|
141
135
|
sty = ssm.get_scheme("molokai_edit")
|
@@ -179,73 +173,69 @@ def gui_set_buffer_contents(id, txt)
|
|
179
173
|
vma.gui.buffers[id].buffer.set_text(txt)
|
180
174
|
end
|
181
175
|
|
176
|
+
#TODO: remove
|
182
177
|
def gui_set_cursor_pos(id, pos)
|
183
178
|
vma.buf.view.set_cursor_pos(pos)
|
184
179
|
end
|
185
180
|
|
186
181
|
def gui_set_current_buffer(id)
|
187
|
-
|
188
|
-
|
189
|
-
buf1 = view.buffer
|
190
|
-
$vmag.view = view
|
191
|
-
$vmag.buf1 = buf1
|
192
|
-
$view = view
|
193
|
-
$vbuf = buf1
|
194
|
-
|
195
|
-
$vmag.sw.remove($vmag.sw.child) if !$vmag.sw.child.nil?
|
196
|
-
$vmag.sw.add(view)
|
197
|
-
|
198
|
-
view.grab_focus
|
199
|
-
view.set_cursor_visible(true)
|
200
|
-
view.place_cursor_onscreen
|
201
|
-
|
202
|
-
$vmag.sw.show_all
|
182
|
+
vma.gui.set_current_buffer(id)
|
183
|
+
return
|
203
184
|
end
|
204
185
|
|
205
186
|
def gui_set_window_title(wtitle, subtitle = "")
|
206
187
|
$vmag.window.title = wtitle
|
207
|
-
$vmag.
|
188
|
+
# $vmag.subtitle.markup = "<span weight='ultrabold'>#{subtitle}</span>"
|
189
|
+
$vmag.subtitle.markup = "<span weight='light' size='small'>#{subtitle}</span>"
|
190
|
+
# $vmag.window.titlebar.subtitle = subtitle #TODO:gtk4
|
208
191
|
end
|
209
192
|
|
210
193
|
class VMAgui
|
211
|
-
attr_accessor :buffers, :sw, :view, :buf1, :window, :delex, :statnfo
|
212
|
-
|
213
|
-
VERSION = "1.0"
|
214
|
-
|
215
|
-
HEART = "♥"
|
216
|
-
RADIUS = 150
|
217
|
-
N_WORDS = 5
|
218
|
-
FONT = "Serif 18"
|
219
|
-
TEXT = "I ♥ GTK+"
|
194
|
+
attr_accessor :buffers, :sw, :sw1, :sw2, :view, :buf1, :window, :delex, :statnfo, :overlay, :overlay1, :overlay2, :sws, :two_c
|
195
|
+
attr_reader :two_column, :windows, :subtitle, :app
|
220
196
|
|
221
197
|
def initialize()
|
198
|
+
@two_column = false
|
199
|
+
@active_column = 1
|
222
200
|
@show_overlay = true
|
223
201
|
@da = nil
|
202
|
+
@sws = []
|
224
203
|
@buffers = {}
|
225
204
|
@view = nil
|
226
205
|
@buf1 = nil
|
227
206
|
@img_resizer_active = false
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
207
|
+
@windows = {}
|
208
|
+
@app = nil
|
209
|
+
# imgproc = proc {
|
210
|
+
# GLib::Idle.add(proc {
|
211
|
+
# if !buf.images.empty?
|
212
|
+
# vma.gui.scale_all_images
|
213
|
+
|
214
|
+
# w = Gtk::Window.new(:toplevel)
|
215
|
+
# w.set_default_size(1, 1)
|
216
|
+
# w.show_all
|
217
|
+
# Thread.new { sleep 0.1; w.destroy }
|
218
|
+
# end
|
219
|
+
|
220
|
+
# false
|
221
|
+
# })
|
222
|
+
# }
|
223
|
+
# @delex = DelayExecutioner.new(1, imgproc)
|
243
224
|
end
|
244
225
|
|
245
226
|
def run
|
246
227
|
init_window
|
247
228
|
# init_rtext
|
248
|
-
|
229
|
+
end
|
230
|
+
|
231
|
+
def quit
|
232
|
+
@window.destroy
|
233
|
+
@shutdown = true
|
234
|
+
for t in Thread.list
|
235
|
+
if t != Thread.current
|
236
|
+
t.exit
|
237
|
+
end
|
238
|
+
end
|
249
239
|
end
|
250
240
|
|
251
241
|
def delay_scale()
|
@@ -254,22 +244,21 @@ class VMAgui
|
|
254
244
|
end
|
255
245
|
|
256
246
|
def scale_all_images
|
257
|
-
|
247
|
+
debug "scale all", 2
|
258
248
|
for img in buf.images
|
259
249
|
if !img[:obj].destroyed?
|
260
250
|
img[:obj].scale_image
|
261
251
|
end
|
262
252
|
end
|
253
|
+
false
|
263
254
|
end
|
264
255
|
|
265
|
-
def handle_image_resize
|
256
|
+
def handle_image_resize #TODO:gtk4
|
266
257
|
return if @img_resizer_active == true
|
267
258
|
@dtime = Time.now
|
268
259
|
|
269
260
|
$gcrw = 0
|
270
261
|
vma.gui.window.signal_connect "configure-event" do |widget, cr|
|
271
|
-
# Ripl.start :binding => binding
|
272
|
-
|
273
262
|
if $gcrw != cr.width
|
274
263
|
@delex.run
|
275
264
|
end
|
@@ -283,12 +272,14 @@ class VMAgui
|
|
283
272
|
def start_overlay_draw()
|
284
273
|
@da = Gtk::Fixed.new
|
285
274
|
@overlay.add_overlay(@da)
|
286
|
-
|
275
|
+
|
276
|
+
# @overlay.set_overlay_pass_through(@da, true) #TODO:gtk4
|
287
277
|
end
|
288
278
|
|
289
279
|
def clear_overlay()
|
290
280
|
if @da != nil
|
291
|
-
@overlay.remove(@da)
|
281
|
+
# @overlay.remove(@da)
|
282
|
+
@overlay.remove_overlay(@da)
|
292
283
|
end
|
293
284
|
end
|
294
285
|
|
@@ -302,72 +293,56 @@ class VMAgui
|
|
302
293
|
end
|
303
294
|
|
304
295
|
def end_overlay_draw()
|
305
|
-
@da.
|
296
|
+
@da.show
|
306
297
|
end
|
307
298
|
|
308
|
-
def
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
@overlay.remove(@da)
|
313
|
-
end
|
314
|
-
return
|
315
|
-
else
|
316
|
-
@da = Gtk::Fixed.new
|
317
|
-
@overlay.add_overlay(@da)
|
318
|
-
@overlay.set_overlay_pass_through(@da, true)
|
299
|
+
def remove_overlay_cursor()
|
300
|
+
if !@cursorov.nil?
|
301
|
+
@overlay.remove_overlay(@cursorov)
|
302
|
+
@cursorov = nil
|
319
303
|
end
|
304
|
+
end
|
320
305
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
# endpos = @view.get_iter_at_position_raw(vr.x+vr.width,vr.y+vr.height)[1].offset
|
334
|
-
# debug "startpos,endpos:#{[startpos, endpos]}"
|
335
|
-
|
336
|
-
da = @da
|
337
|
-
if false
|
338
|
-
da.signal_connect "draw" do |widget, cr|
|
339
|
-
cr.save
|
340
|
-
for pos in wpos
|
341
|
-
(x, y) = @view.pos_to_coord(pos)
|
342
|
-
|
343
|
-
layout = da.create_pango_layout("XY")
|
344
|
-
desc = Pango::FontDescription.new("sans bold 11")
|
345
|
-
layout.font_description = desc
|
346
|
-
|
347
|
-
cr.move_to(x, y)
|
348
|
-
# cr.move_to(gutter_width, 300)
|
349
|
-
cr.pango_layout_path(layout)
|
350
|
-
|
351
|
-
cr.set_source_rgb(1.0, 0.0, 0.0)
|
352
|
-
cr.fill_preserve
|
353
|
-
end
|
354
|
-
cr.restore
|
355
|
-
false # = draw other
|
356
|
-
# true # = Don't draw others
|
306
|
+
def overlay_draw_cursor(textpos)
|
307
|
+
# return
|
308
|
+
remove_overlay_cursor
|
309
|
+
GLib::Idle.add(proc { self.overlay_draw_cursor_(textpos) })
|
310
|
+
# overlay_draw_cursor_(textpos)
|
311
|
+
end
|
312
|
+
|
313
|
+
# Run proc after animated scrolling has stopped (e.g. after page down)
|
314
|
+
def run_after_scrolling(p)
|
315
|
+
Thread.new {
|
316
|
+
while Time.now - @last_adj_time < 0.1
|
317
|
+
sleep 0.1
|
357
318
|
end
|
358
|
-
|
319
|
+
run_as_idle p
|
320
|
+
}
|
321
|
+
end
|
359
322
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
323
|
+
# To draw on empty lines and line-ends (where select_range doesn't work)
|
324
|
+
def overlay_draw_cursor_(textpos)
|
325
|
+
# Thread.new {
|
326
|
+
# GLib::Idle.add(proc { p.call; false })
|
327
|
+
# }
|
328
|
+
|
329
|
+
# while Time.now - @last_adj_time < 0.3
|
330
|
+
# return true
|
331
|
+
# end
|
367
332
|
|
368
|
-
|
333
|
+
remove_overlay_cursor
|
334
|
+
@cursorov = Gtk::Fixed.new
|
335
|
+
@overlay.add_overlay(@cursorov)
|
369
336
|
|
370
|
-
@
|
337
|
+
(x, y) = @view.pos_to_coord(textpos)
|
338
|
+
pp [x, y]
|
339
|
+
|
340
|
+
# Trying to draw only background of character "I"
|
341
|
+
label = Gtk::Label.new("<span background='#00ffaaff' foreground='#00ffaaff' weight='ultrabold'>I</span>")
|
342
|
+
label.use_markup = true
|
343
|
+
@cursorov.put(label, x, y)
|
344
|
+
@cursorov.show
|
345
|
+
return false
|
371
346
|
end
|
372
347
|
|
373
348
|
def handle_deltas()
|
@@ -388,6 +363,7 @@ class VMAgui
|
|
388
363
|
end
|
389
364
|
|
390
365
|
def add_to_minibuf(msg)
|
366
|
+
# return #TODO:gtk4
|
391
367
|
startiter = @minibuf.buffer.get_iter_at(:offset => 0)
|
392
368
|
@minibuf.buffer.insert(startiter, "#{msg}\n")
|
393
369
|
@minibuf.signal_emit("move-cursor", Gtk::MovementStep.new(:PAGES), -1, false)
|
@@ -398,12 +374,8 @@ class VMAgui
|
|
398
374
|
sw = Gtk::ScrolledWindow.new
|
399
375
|
sw.set_policy(:automatic, :automatic)
|
400
376
|
overlay = Gtk::Overlay.new
|
401
|
-
overlay.
|
402
|
-
|
403
|
-
@vbox.attach(overlay, 0, 2, 2, 1)
|
404
|
-
# overlay.set_size_request(-1, 50)
|
405
|
-
# $ovrl = overlay
|
406
|
-
# $ovrl.set_size_request(-1, 30)
|
377
|
+
overlay.set_child(sw)
|
378
|
+
@vbox.attach(overlay, 0, 3, 2, 1)
|
407
379
|
$sw2 = sw
|
408
380
|
sw.set_size_request(-1, 12)
|
409
381
|
|
@@ -418,22 +390,21 @@ class VMAgui
|
|
418
390
|
view.buffer.style_scheme = sty
|
419
391
|
provider = Gtk::CssProvider.new
|
420
392
|
# provider.load(data: "textview { font-family: Monospace; font-size: 11pt; }")
|
421
|
-
provider.load(data: "textview { font-family: Arial; font-size: 10pt; color:#
|
393
|
+
provider.load(data: "textview { font-family: Arial; font-size: 10pt; color:#eeeeee}")
|
422
394
|
view.style_context.add_provider(provider)
|
423
395
|
view.wrap_mode = :char
|
424
396
|
@minibuf = view
|
425
|
-
# Ripl.start :binding => binding
|
426
397
|
# startiter = view.buffer.get_iter_at(:offset => 0)
|
427
398
|
message("STARTUP")
|
428
|
-
sw.
|
399
|
+
sw.set_child(view)
|
429
400
|
end
|
430
401
|
|
431
402
|
def init_header_bar()
|
432
403
|
header = Gtk::HeaderBar.new
|
433
404
|
@header = header
|
434
405
|
header.show_close_button = true
|
435
|
-
header.title = ""
|
436
|
-
header.has_subtitle = true
|
406
|
+
# header.title = ""#TODO:gtk4
|
407
|
+
# header.has_subtitle = true#TODO:gtk4
|
437
408
|
header.subtitle = ""
|
438
409
|
|
439
410
|
# icon = Gio::ThemedIcon.new("mail-send-receive-symbolic")
|
@@ -513,55 +484,422 @@ class VMAgui
|
|
513
484
|
# @window.add(Gtk::TextView.new)
|
514
485
|
end
|
515
486
|
|
487
|
+
def debug_idle_func
|
488
|
+
return false if @shutdown == true
|
489
|
+
if Time.now - @last_debug_idle > 1
|
490
|
+
@last_debug_idle = Time.now
|
491
|
+
# puts "DEBUG IDLE #{Time.now}"
|
492
|
+
# @view.check_controllers
|
493
|
+
end
|
494
|
+
|
495
|
+
ctrl_fn = File.expand_path("~/.vimamsa/ripl_ctrl")
|
496
|
+
# Allows to debug in case keyboard handling is lost
|
497
|
+
if File.exist?(ctrl_fn)
|
498
|
+
File.delete(ctrl_fn)
|
499
|
+
start_ripl
|
500
|
+
end
|
501
|
+
|
502
|
+
sleep 0.02
|
503
|
+
return true
|
504
|
+
end
|
505
|
+
|
506
|
+
# Remove widget event controllers added by gtk, and add our own.
|
507
|
+
def reset_controllers
|
508
|
+
clist = @window.observe_controllers
|
509
|
+
to_remove = []
|
510
|
+
(0..(clist.n_items - 1)).each { |x|
|
511
|
+
ctr = clist.get_item(x)
|
512
|
+
if ctr.class == Gtk::EventControllerKey
|
513
|
+
to_remove << ctr
|
514
|
+
end
|
515
|
+
}
|
516
|
+
if to_remove.size > 0
|
517
|
+
puts "Removing controllers:"
|
518
|
+
pp to_remove
|
519
|
+
to_remove.each { |x| @window.remove_controller(x) }
|
520
|
+
end
|
521
|
+
|
522
|
+
press = Gtk::EventControllerKey.new
|
523
|
+
@press = press
|
524
|
+
# to prevent SourceView key handler capturing any keypresses
|
525
|
+
press.set_propagation_phase(Gtk::PropagationPhase::CAPTURE)
|
526
|
+
@window.add_controller(press)
|
527
|
+
|
528
|
+
press.signal_connect "key-pressed" do |gesture, keyval, keycode, y|
|
529
|
+
name = Gdk::Keyval.to_name(keyval)
|
530
|
+
uki = Gdk::Keyval.to_unicode(keyval)
|
531
|
+
keystr = uki.chr("UTF-8")
|
532
|
+
puts "key-pressed #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
|
533
|
+
buf.view.handle_key_event(keyval, keystr, :key_press)
|
534
|
+
true
|
535
|
+
end
|
536
|
+
|
537
|
+
press.signal_connect "modifiers" do |eventctr, modtype|
|
538
|
+
# eventctr: Gtk::EventControllerKey
|
539
|
+
# modtype: Gdk::ModifierType
|
540
|
+
debug "modifier change"
|
541
|
+
vma.kbd.modifiers[:ctrl] = modtype.control_mask?
|
542
|
+
vma.kbd.modifiers[:alt] = modtype.alt_mask?
|
543
|
+
vma.kbd.modifiers[:hyper] = modtype.hyper_mask?
|
544
|
+
vma.kbd.modifiers[:lock] = modtype.lock_mask?
|
545
|
+
vma.kbd.modifiers[:meta] = modtype.meta_mask?
|
546
|
+
vma.kbd.modifiers[:shift] = modtype.shift_mask?
|
547
|
+
vma.kbd.modifiers[:super] = modtype.super_mask?
|
548
|
+
|
549
|
+
#TODO:?
|
550
|
+
# button1_mask?
|
551
|
+
# ...
|
552
|
+
# button5_mask?
|
553
|
+
true
|
554
|
+
end
|
555
|
+
|
556
|
+
press.signal_connect "key-released" do |gesture, keyval, keycode, y|
|
557
|
+
name = Gdk::Keyval.to_name(keyval)
|
558
|
+
uki = Gdk::Keyval.to_unicode(keyval)
|
559
|
+
keystr = uki.chr("UTF-8")
|
560
|
+
puts "key released #{keyval} #{keycode} name:#{name} str:#{keystr} unicode:#{uki}"
|
561
|
+
buf.view.handle_key_event(keyval, keystr, :key_release)
|
562
|
+
# vma.kbd.match_key_conf(keystr, nil, :key_press)
|
563
|
+
# buf.view.handle_deltas
|
564
|
+
# buf.view.handle_key_event(keyval, keystr, :key_press)
|
565
|
+
true
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
def remove_extra_controllers
|
570
|
+
clist = vma.gui.window.observe_controllers
|
571
|
+
to_remove = []
|
572
|
+
(0..(clist.n_items - 1)).each { |x|
|
573
|
+
ctr = clist.get_item(x)
|
574
|
+
if ctr.class == Gtk::EventControllerKey and ctr != @press
|
575
|
+
to_remove << ctr
|
576
|
+
end
|
577
|
+
}
|
578
|
+
if to_remove.size > 0
|
579
|
+
puts "Removing controllers:"
|
580
|
+
pp to_remove
|
581
|
+
to_remove.each { |x| vma.gui.window.remove_controller(x) }
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def idle_set_size()
|
586
|
+
# Need to wait for a while to window to be maximized to get correct @window.width
|
587
|
+
sleep 0.1
|
588
|
+
width = @window.width / 2
|
589
|
+
height = @window.height - 5
|
590
|
+
# Ripl.start :binding => binding
|
591
|
+
@window.unmaximize
|
592
|
+
@window.set_size_request(width, height)
|
593
|
+
return false
|
594
|
+
end
|
595
|
+
|
516
596
|
def init_window
|
517
|
-
@
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
597
|
+
@last_debug_idle = Time.now
|
598
|
+
app = Gtk::Application.new("net.samiddhi.vimamsa.r#{rand(1000)}", :flags_none)
|
599
|
+
@app = app
|
600
|
+
|
601
|
+
Gtk::Settings.default.gtk_application_prefer_dark_theme = true
|
602
|
+
Gtk::Settings.default.gtk_theme_name = "Adwaita"
|
603
|
+
|
604
|
+
app.signal_connect "activate" do
|
605
|
+
@window = Gtk::ApplicationWindow.new(app)
|
606
|
+
@window.set_application(app)
|
607
|
+
|
608
|
+
@window.maximize
|
609
|
+
# Need to let Gtk process after maximize
|
610
|
+
run_as_idle proc { idle_set_size }
|
611
|
+
|
612
|
+
@window.title = "Multiple Views"
|
613
|
+
@vpaned = Gtk::Paned.new(:vertical)
|
614
|
+
|
615
|
+
@vbox = Gtk::Grid.new()
|
616
|
+
@window.add(@vbox)
|
617
|
+
|
618
|
+
Thread.new {
|
619
|
+
GLib::Idle.add(proc { debug_idle_func })
|
620
|
+
}
|
621
|
+
|
622
|
+
reset_controllers
|
623
|
+
|
624
|
+
@sw = Gtk::ScrolledWindow.new
|
625
|
+
@sw.set_policy(:automatic, :automatic)
|
626
|
+
|
627
|
+
@last_adj_time = Time.now
|
628
|
+
@sw.vadjustment.signal_connect("value-changed") { |x|
|
629
|
+
# pp x.page_increment
|
630
|
+
# pp x.page_size
|
631
|
+
# pp x.step_increment
|
632
|
+
# pp x.upper
|
633
|
+
# pp x.value
|
634
|
+
# pp x
|
635
|
+
@last_adj_time = Time.now
|
636
|
+
# puts "@sw.vadjustment"
|
637
|
+
}
|
638
|
+
|
639
|
+
# @sw.signal_connect("clicked") { puts "Hello World!" }
|
640
|
+
# @sw.signal_connect("key-pressed") { puts "Hello World!" }
|
641
|
+
@overlay = Gtk::Overlay.new
|
642
|
+
# @overlay.add(@sw) #TODO:gtk4
|
643
|
+
@overlay.add_overlay(@sw) #TODO:gtk4
|
644
|
+
@overlay1 = @overlay
|
645
|
+
|
646
|
+
# init_header_bar #TODO:gtk4
|
647
|
+
|
648
|
+
@statnfo = Gtk::Label.new
|
649
|
+
@subtitle = Gtk::Label.new("")
|
650
|
+
@statbox = Gtk::Box.new(:horizontal, 2)
|
651
|
+
@statnfo.set_size_request(150, 10)
|
652
|
+
@statbox.pack_end(@subtitle, :expand => true, :fill => true, :padding => 0)
|
653
|
+
@statbox.pack_end(@statnfo, :expand => false, :fill => false, :padding => 0)
|
654
|
+
provider = Gtk::CssProvider.new
|
655
|
+
@statnfo.add_css_class("statnfo")
|
656
|
+
provider.load(data: "label.statnfo { background-color:#353535; font-size: 10pt; margin-top:2px; margin-bottom:2px; align:right;}")
|
657
|
+
|
658
|
+
provider = Gtk::CssProvider.new
|
659
|
+
@statnfo.style_context.add_provider(provider)
|
660
|
+
|
661
|
+
# numbers: left, top, width, height
|
662
|
+
@vbox.attach(@overlay, 0, 2, 2, 1)
|
663
|
+
@sw.vexpand = true
|
664
|
+
@sw.hexpand = true
|
665
|
+
|
666
|
+
# column, row, width height
|
667
|
+
@vbox.attach(@statbox, 1, 1, 1, 1)
|
668
|
+
|
669
|
+
@overlay.vexpand = true
|
670
|
+
@overlay.hexpand = true
|
671
|
+
|
672
|
+
init_minibuffer
|
673
|
+
|
674
|
+
# p = Gtk::Popover.new
|
675
|
+
|
676
|
+
name = "save"
|
677
|
+
window = @window
|
678
|
+
action = Gio::SimpleAction.new(name)
|
679
|
+
action.signal_connect "activate" do |_simple_action, _parameter|
|
680
|
+
dialog = Gtk::MessageDialog.new(:parent => window,
|
681
|
+
:flags => :destroy_with_parent,
|
682
|
+
:buttons => :close,
|
683
|
+
:message => "Action FOOBAR activated.")
|
684
|
+
dialog.signal_connect(:response) do
|
685
|
+
dialog.destroy
|
686
|
+
end
|
687
|
+
dialog.show
|
688
|
+
end
|
522
689
|
|
523
|
-
|
524
|
-
|
525
|
-
|
690
|
+
@window.add_action(action)
|
691
|
+
doc_actions = Gio::SimpleActionGroup.new
|
692
|
+
doc_actions.add_action(action)
|
526
693
|
|
527
|
-
|
528
|
-
|
694
|
+
act_quit = Gio::SimpleAction.new("quit")
|
695
|
+
app.add_action(act_quit)
|
696
|
+
act_quit.signal_connect "activate" do |_simple_action, _parameter|
|
697
|
+
window.destroy
|
698
|
+
exit!
|
699
|
+
end
|
529
700
|
|
530
|
-
|
531
|
-
|
701
|
+
menubar = Gio::Menu.new
|
702
|
+
app.menubar = menubar
|
703
|
+
@window.show_menubar = true
|
532
704
|
|
533
|
-
|
534
|
-
@sw.set_policy(:automatic, :automatic)
|
535
|
-
@overlay = Gtk::Overlay.new
|
536
|
-
@overlay.add(@sw)
|
705
|
+
@menubar = menubar
|
537
706
|
|
538
|
-
|
707
|
+
@windows[1] = { :sw => @sw, :overlay => @overlay, :id => 1 }
|
708
|
+
@active_window = @windows[1]
|
539
709
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
710
|
+
@window.show
|
711
|
+
|
712
|
+
press = Gtk::GestureClick.new
|
713
|
+
press.button = Gdk::BUTTON_SECONDARY
|
714
|
+
@window.add_controller(press)
|
715
|
+
press.signal_connect "pressed" do |gesture, n_press, x, y|
|
716
|
+
puts "FOOBARpressed"
|
717
|
+
# clear_surface(surface)
|
718
|
+
# drawing_area.queue_draw
|
719
|
+
end
|
720
|
+
@sw1 = @sw
|
721
|
+
|
722
|
+
prov = Gtk::CssProvider.new
|
723
|
+
# See gtk-4.9.4/gtk/theme/Default/_common.scss on how to theme
|
724
|
+
# gtksourceview/gtksourcestyleschemepreview.c
|
725
|
+
# gtksourceview/gtksourcestylescheme.c
|
726
|
+
prov.load(data: " headerbar { padding: 0 0px; min-height: 16px; border-width: 0 0 0px; border-style: solid; }
|
727
|
+
|
728
|
+
textview border.left gutter { color: #8aa; font-size:8pt; }
|
729
|
+
|
730
|
+
textview border.left gutter { padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px; color: #8aa; font-size:9pt; }
|
731
|
+
|
732
|
+
headerbar .title {
|
733
|
+
font-weight: bold;
|
734
|
+
font-size: 11pt;
|
735
|
+
color: #cdffee;
|
736
|
+
}
|
737
|
+
|
738
|
+
headerbar > windowhandle > box .start {
|
739
|
+
border-spacing: 6px;
|
740
|
+
}
|
741
|
+
|
742
|
+
headerbar windowcontrols button {
|
743
|
+
min-height: 15px;
|
744
|
+
min-width: 15px;
|
745
|
+
}
|
746
|
+
|
747
|
+
")
|
748
|
+
@window.style_context.add_provider(prov)
|
749
|
+
|
750
|
+
sc = Gtk::StyleContext.add_provider_for_display(Gdk::Display.default, prov)
|
751
|
+
|
752
|
+
vma.start
|
753
|
+
end
|
754
|
+
|
755
|
+
# Vimamsa::Menu.new(@menubar) #TODO:gtk4
|
756
|
+
app.run
|
757
|
+
|
758
|
+
# @window.show_all
|
759
|
+
# @window.show
|
760
|
+
end
|
761
|
+
|
762
|
+
def init_menu
|
763
|
+
Vimamsa::Menu.new(@menubar, @app)
|
764
|
+
end
|
765
|
+
|
766
|
+
def set_two_column
|
767
|
+
return if @two_column
|
768
|
+
# @window.set_default_size(800, 600) #TODO:gtk4
|
769
|
+
# @vpaned = Gtk::Paned.new(:vertical)
|
770
|
+
# @vbox = Gtk::Grid.new()
|
771
|
+
# @window.add(@vbox)
|
772
|
+
|
773
|
+
@sw2 = Gtk::ScrolledWindow.new
|
774
|
+
@sw2.set_policy(:automatic, :automatic)
|
775
|
+
@overlay2 = Gtk::Overlay.new
|
776
|
+
@overlay2.add_overlay(@sw2)
|
777
|
+
@pane = Gtk::Paned.new(:horizontal)
|
778
|
+
|
779
|
+
@windows[2] = { :sw => @sw2, :overlay => @overlay2, :id => 2 }
|
780
|
+
|
781
|
+
@vbox.remove(@overlay)
|
782
|
+
|
783
|
+
# numbers: left, top, width, height
|
784
|
+
@pane.set_start_child(@overlay2)
|
785
|
+
@pane.set_end_child(@overlay)
|
786
|
+
|
787
|
+
@vbox.attach(@pane, 0, 2, 2, 1)
|
788
|
+
|
789
|
+
@sw2.vexpand = true
|
790
|
+
@sw2.hexpand = true
|
791
|
+
|
792
|
+
@overlay2.vexpand = true
|
793
|
+
@overlay2.hexpand = true
|
794
|
+
|
795
|
+
@sw2.show
|
796
|
+
@two_column = true
|
797
|
+
|
798
|
+
if vma.buffers.size > 1
|
799
|
+
last = vma.buffers.get_last_visited_id
|
800
|
+
set_buffer_to_window(last, 2)
|
801
|
+
else
|
802
|
+
bf = create_new_buffer "\n\n", "buff", false
|
803
|
+
set_buffer_to_window(bf.id, 2)
|
804
|
+
end
|
805
|
+
end
|
544
806
|
|
545
|
-
|
546
|
-
|
547
|
-
|
807
|
+
def is_buffer_open(bufid)
|
808
|
+
openbufids = @windows.keys.collect { |x| @windows[x][:sw].child.bufo.id }
|
809
|
+
return openbufids.include?(bufid)
|
810
|
+
end
|
811
|
+
|
812
|
+
def toggle_active_window()
|
813
|
+
return if !@two_column
|
814
|
+
if @active_column == 1
|
815
|
+
set_active_window(2)
|
816
|
+
else
|
817
|
+
set_active_window(1)
|
818
|
+
end
|
819
|
+
end
|
548
820
|
|
549
|
-
|
550
|
-
|
551
|
-
@
|
552
|
-
|
553
|
-
|
554
|
-
|
821
|
+
# activate that window which has the given view
|
822
|
+
def set_current_view(view)
|
823
|
+
w = @windows.find { |k, v| v[:sw].child == view }
|
824
|
+
if !w.nil?
|
825
|
+
set_active_window(w[0])
|
826
|
+
end
|
827
|
+
end
|
555
828
|
|
556
|
-
|
557
|
-
|
829
|
+
def set_active_window(id)
|
830
|
+
return if !@two_column
|
831
|
+
return if id == @active_column
|
832
|
+
return if id == @active_window[:id]
|
558
833
|
|
559
|
-
|
834
|
+
if @windows[id].nil?
|
835
|
+
debug "No such window #{id}", 2
|
836
|
+
return
|
837
|
+
end
|
838
|
+
|
839
|
+
@active_window = @windows[id]
|
840
|
+
@active_column = id #TODO: remove
|
841
|
+
|
842
|
+
@sw = @windows[id][:sw]
|
843
|
+
@overlay = @windows[id][:overlay]
|
844
|
+
|
845
|
+
vma.buffers.set_current_buffer_by_id(@sw.child.bufo.id)
|
846
|
+
|
847
|
+
#TODO: set buf & view of active window??
|
848
|
+
|
849
|
+
end
|
560
850
|
|
561
|
-
|
562
|
-
|
563
|
-
|
851
|
+
def current_view
|
852
|
+
return @sw.child
|
853
|
+
end
|
854
|
+
|
855
|
+
def set_buffer_to_window(bufid, winid)
|
856
|
+
view = @buffers[bufid]
|
857
|
+
debug "vma.gui.set_buffer_to_window(#{bufid}), winid=#{winid}"
|
858
|
+
buf1 = view.buffer
|
859
|
+
|
860
|
+
@windows[winid][:sw].set_child(view)
|
861
|
+
idle_ensure_cursor_drawn
|
862
|
+
|
863
|
+
# @overlay = Gtk::Overlay.new
|
864
|
+
# @overlay.add_overlay(view)
|
865
|
+
|
866
|
+
#TODO:???
|
867
|
+
# @view = view
|
868
|
+
# @buf1 = buf1
|
869
|
+
# $view = view ???
|
870
|
+
# $vbuf = buf1
|
871
|
+
|
872
|
+
end
|
873
|
+
|
874
|
+
def set_current_buffer(id)
|
875
|
+
view = @buffers[id]
|
876
|
+
debug "vma.gui.set_current_buffer(#{id}), view=#{view}"
|
877
|
+
buf1 = view.buffer
|
878
|
+
@view = view
|
879
|
+
@buf1 = buf1
|
880
|
+
$view = view
|
881
|
+
$vbuf = buf1
|
882
|
+
|
883
|
+
# Check if buffer is already open in another column
|
884
|
+
if @two_column and @active_column == 2 and id == @sw1.child.bufo.id
|
885
|
+
toggle_active_window
|
886
|
+
elsif @two_column && @active_column == 1 && !@sw2.child.nil? && id == @sw2.child.bufo.id
|
887
|
+
#TODO: should not need !@sw2.child.nil? here. If this happens then other column is empty.
|
888
|
+
toggle_active_window
|
889
|
+
else
|
890
|
+
@sw.set_child(view)
|
891
|
+
end
|
892
|
+
view.grab_focus
|
893
|
+
|
894
|
+
idle_ensure_cursor_drawn
|
895
|
+
end
|
896
|
+
|
897
|
+
def idle_ensure_cursor_drawn
|
898
|
+
run_as_idle proc { self.ensure_cursor_drawn }
|
899
|
+
end
|
564
900
|
|
565
|
-
|
901
|
+
def ensure_cursor_drawn
|
902
|
+
# view.place_cursor_onscreen #TODO: needed?
|
903
|
+
view.draw_cursor
|
566
904
|
end
|
567
905
|
end
|