vimamsa 0.1.10 → 0.1.12
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/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
|