rbcurse 0.1.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/CHANGELOG +126 -0
  2. data/Manifest.txt +53 -20
  3. data/README.markdown +423 -0
  4. data/Rakefile +3 -1
  5. data/examples/keytest.rb +177 -0
  6. data/examples/mpad2.rb +156 -0
  7. data/examples/newtesttabp.rb +121 -0
  8. data/examples/rfe.rb +48 -10
  9. data/examples/rfe_renderer.rb +4 -4
  10. data/examples/rvimsplit.rb +376 -0
  11. data/examples/sqlc.rb +97 -106
  12. data/examples/sqlm.rb +446 -0
  13. data/examples/test1.rb +4 -4
  14. data/examples/test2.rb +12 -12
  15. data/examples/testchars.rb +140 -0
  16. data/examples/testkeypress.rb +9 -4
  17. data/examples/testmulticomp.rb +72 -0
  18. data/examples/testscroller.rb +136 -0
  19. data/examples/testscrolllb.rb +86 -0
  20. data/examples/testscrollp.rb +87 -0
  21. data/examples/testscrollta.rb +80 -0
  22. data/examples/testscrolltable.rb +166 -0
  23. data/examples/testsplit.rb +87 -0
  24. data/examples/testsplit2.rb +123 -0
  25. data/examples/testsplit3.rb +215 -0
  26. data/examples/testsplit3_1.rb +244 -0
  27. data/examples/testsplit3a.rb +215 -0
  28. data/examples/testsplit3b.rb +237 -0
  29. data/examples/testsplitta.rb +148 -0
  30. data/examples/testsplittv.rb +142 -0
  31. data/examples/testsplittvv.rb +144 -0
  32. data/examples/testtable.rb +1 -1
  33. data/examples/testtabp.rb +3 -2
  34. data/examples/testtestw.rb +69 -0
  35. data/examples/testtodo.rb +5 -3
  36. data/examples/testtpane.rb +203 -0
  37. data/examples/testtpane2.rb +145 -0
  38. data/examples/testtpanetable.rb +199 -0
  39. data/examples/viewtodo.rb +5 -3
  40. data/lib/rbcurse.rb +1 -1
  41. data/lib/rbcurse/celleditor.rb +2 -2
  42. data/lib/rbcurse/colormap.rb +5 -5
  43. data/lib/rbcurse/defaultlistselectionmodel.rb +3 -3
  44. data/lib/rbcurse/io.rb +663 -0
  45. data/lib/rbcurse/listeditable.rb +306 -0
  46. data/lib/rbcurse/listkeys.rb +15 -15
  47. data/lib/rbcurse/listscrollable.rb +168 -27
  48. data/lib/rbcurse/mapper.rb +35 -13
  49. data/lib/rbcurse/rchangeevent.rb +28 -0
  50. data/lib/rbcurse/rform.rb +845 -0
  51. data/lib/rbcurse/rlistbox.rb +144 -34
  52. data/lib/rbcurse/rmessagebox.rb +10 -5
  53. data/lib/rbcurse/rmulticontainer.rb +325 -0
  54. data/lib/rbcurse/rmultitextview.rb +306 -0
  55. data/lib/rbcurse/rscrollform.rb +369 -0
  56. data/lib/rbcurse/rscrollpane.rb +511 -0
  57. data/lib/rbcurse/rsplitpane.rb +820 -0
  58. data/lib/rbcurse/rtabbedpane.rb +737 -109
  59. data/lib/rbcurse/rtabbedwindow.rb +326 -0
  60. data/lib/rbcurse/rtable.rb +220 -64
  61. data/lib/rbcurse/rtextarea.rb +340 -181
  62. data/lib/rbcurse/rtextview.rb +237 -101
  63. data/lib/rbcurse/rviewport.rb +203 -0
  64. data/lib/rbcurse/rwidget.rb +919 -95
  65. data/lib/rbcurse/scrollable.rb +7 -7
  66. data/lib/rbcurse/selectable.rb +4 -4
  67. data/lib/rbcurse/table/tablecellrenderer.rb +3 -0
  68. data/lib/rbcurse/undomanager.rb +181 -0
  69. data/lib/rbcurse/vieditable.rb +100 -0
  70. data/lib/ver/window.rb +471 -21
  71. metadata +66 -22
  72. data/README.txt +0 -312
  73. data/examples/testd.db +0 -0
  74. data/examples/todocsv.csv +0 -28
@@ -102,8 +102,6 @@ module RubyCurses
102
102
  def delete obj
103
103
  off0 = @list.index obj
104
104
  return nil if off0.nil?
105
- # 2009-11-04 11:33 next line corrected to delete_at
106
- #ret=@list.delete off0
107
105
  ret=@list.delete_at off0
108
106
  lde = ListDataEvent.new(off0, off0, self, :INTERVAL_REMOVED)
109
107
  fire_handler :LIST_DATA_EVENT, lde
@@ -207,7 +205,7 @@ module RubyCurses
207
205
  instance_eval &block if block_given?
208
206
  @list_config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
209
207
  @height ||= [@max_visible_items || 10, @list.length].min
210
- #$log.debug " POPUP XXX #{@max_visible_items} ll:#{@list.length} h:#{@height}"
208
+ $log.debug " POPUP XXX #{@max_visible_items} ll:#{@list.length} h:#{@height}"
211
209
  # get widgets absolute coords
212
210
  if !@relative_to.nil?
213
211
  layout = @relative_to.form.window.layout
@@ -232,15 +230,9 @@ module RubyCurses
232
230
  @window = VER::Window.new(@layout)
233
231
  @form = RubyCurses::Form.new @window
234
232
  @window.bkgd(Ncurses.COLOR_PAIR($reversecolor));
235
- #@window.attron(Ncurses.COLOR_PAIR($reversecolor));
236
- #@window.wclear
237
- #@window.attroff(Ncurses.COLOR_PAIR($reversecolor));
238
233
  @window.wrefresh
239
234
  @panel = @window.panel # useless line ?
240
235
  Ncurses::Panel.update_panels
241
- # @message_row = @message_col = 2
242
- # print_borders
243
- # print_title
244
236
  print_input # creates the listbox
245
237
  @form.repaint
246
238
  @window.wrefresh
@@ -322,8 +314,10 @@ module RubyCurses
322
314
  def print_input
323
315
  r = c = 0
324
316
  width = @layout[:width]
317
+ #$log.debug " print_input POPUP ht:#{@height} lh:#{@layout[:height]} "
325
318
  height = @layout[:height]
326
- height = @height
319
+ #height = @height # 2010-01-06 12:52 why was this overriding previous line. its one less than layout
320
+ # i am now using layout height since it gives a closer size to whats asked for.
327
321
  parent = @relative_to
328
322
  defaultvalue = @default_value || ""
329
323
  list = @list
@@ -345,7 +339,6 @@ module RubyCurses
345
339
  default_values default_values
346
340
  is_popup true
347
341
  #add_observer parent
348
-
349
342
  end
350
343
  end
351
344
  # may need to be upgraded to new one XXX FIXME
@@ -410,6 +403,7 @@ module RubyCurses
410
403
  dsl_accessor :KEY_NEXT_SELECTION
411
404
  dsl_accessor :KEY_PREV_SELECTION
412
405
  dsl_accessor :valign # 2009-01-17 18:32
406
+ attr_accessor :one_key_selection # will pressing a single key select or not
413
407
 
414
408
  def initialize form, config={}, &block
415
409
  @focusable = true
@@ -425,8 +419,15 @@ module RubyCurses
425
419
  @row_offset = @col_offset = 1
426
420
  @content_rows = @list.length
427
421
  @selection_mode ||= 'multiple'
428
- @win = @form.window
429
- print_borders unless @win.nil? # in messagebox we don;t have window as yet!
422
+ @win = @graphic # 2010-01-04 12:36 BUFFERED replace form.window with graphic
423
+ # moving down to repaint so that scrollpane can set should_buffered
424
+ # added 2010-02-17 23:05 RFED16 so we don't need a form.
425
+ @win_left = 0
426
+ @win_top = 0
427
+ @multiplier = 0 # multiply motion commands
428
+
429
+ #x safe_create_buffer # 2010-01-04 12:36 BUFFERED moved here 2010-01-05 18:07
430
+ #x print_borders unless @win.nil? # in messagebox we don;t have window as yet!
430
431
  # next 2 lines carry a redundancy
431
432
  select_default_values
432
433
  # when the combo box has a certain row in focus, the popup should have the same row in focus
@@ -449,6 +450,16 @@ module RubyCurses
449
450
  @left_margin ||= @row_selected_symbol.length
450
451
  end
451
452
  @left_margin ||= 0
453
+ @one_key_selection ||= true
454
+ bind_key(?f){ ask_selection_for_char() }
455
+ bind_key(?\M-v){ @one_key_selection = false }
456
+ bind_key(?j){ next_row() }
457
+ bind_key(?k){ previous_row() }
458
+ bind_key(?G){ goto_bottom() }
459
+ bind_key([?g,?g]){ goto_top() }
460
+ bind_key(?/){ ask_search() }
461
+ bind_key(?n){ find_more() }
462
+
452
463
  end
453
464
  def install_bindings
454
465
 
@@ -470,7 +481,8 @@ module RubyCurses
470
481
  end
471
482
  # added 2009-01-07 13:05 so new scrollable can use
472
483
  def scrollatrow
473
- @height - 2
484
+ #@height - 2
485
+ @height - 3 # 2010-01-04 15:30 BUFFERED HEIGHT
474
486
  end
475
487
  def list alist=nil
476
488
  return @list if alist.nil?
@@ -505,16 +517,22 @@ module RubyCurses
505
517
  end
506
518
  def print_borders
507
519
  width = @width
508
- height = @height
509
- window = @form.window
520
+ height = @height-1 # 2010-01-04 15:30 BUFFERED HEIGHT
521
+ window = @graphic # 2010-01-04 12:37 BUFFERED
510
522
  startcol = @col
511
523
  startrow = @row
512
524
  @color_pair = get_color($datacolor)
525
+ #$log.debug "rlistb: window.print_border #{startrow}, #{startcol} , #{height} , #{width} , @color_pair, @attr "
513
526
  window.print_border startrow, startcol, height, width, @color_pair, @attr
514
527
  print_title
515
528
  end
516
529
  def print_title
517
- printstring(@form.window, @row, @col+(@width-@title.length)/2, @title, @color_pair, @title_attrib) unless @title.nil?
530
+ #printstring(@graphic, @row, @col+(@width-@title.length)/2, @title, @color_pair, @title_attrib) unless @title.nil?
531
+ # 2010-01-04 15:53 BUFFERED
532
+ # I notice that the old version would print a title that was longer than width,
533
+ #+ but the new version won't print anything if it exceeds width.
534
+ # TODO check title.length and truncate if exceeds width
535
+ @graphic.printstring( @row, @col+(@width-@title.length)/2, @title, @color_pair, @title_attrib) unless @title.nil?
518
536
  end
519
537
  ### START FOR scrollable ###
520
538
  def get_content
@@ -522,7 +540,7 @@ module RubyCurses
522
540
  @list_variable && @list_variable.value || @list
523
541
  end
524
542
  def get_window
525
- @form.window
543
+ @graphic # 2010-01-04 12:37 BUFFERED
526
544
  end
527
545
  ### END FOR scrollable ###
528
546
  # override widgets text
@@ -542,18 +560,18 @@ module RubyCurses
542
560
  previous_row
543
561
  when KEY_DOWN # show previous value
544
562
  next_row
545
- when @KEY_ROW_SELECTOR # 32:
563
+ when @KEY_ROW_SELECTOR # 32
546
564
  return if is_popup and @selection_mode == 'single' # not allowing select this way since there will be a difference
547
565
  toggle_row_selection @current_index #, @current_index
548
566
  @repaint_required = true
549
- when @KEY_SCROLL_FORWARD # ?\C-n:
567
+ when @KEY_SCROLL_FORWARD # ?\C-n
550
568
  scroll_forward
551
- when @KEY_SCROLL_BACKWARD # ?\C-p:
569
+ when @KEY_SCROLL_BACKWARD # ?\C-p
552
570
  scroll_backward
553
- when @KEY_GOTO_TOP # 48, ?\C-[:
571
+ when @KEY_GOTO_TOP # 48, ?\C-[
554
572
  # please note that C-[ gives 27, same as esc so will respond after ages
555
573
  goto_top
556
- when @KEY_GOTO_BOTTOM # ?\C-]:
574
+ when @KEY_GOTO_BOTTOM # ?\C-]
557
575
  goto_bottom
558
576
  when @KEY_NEXT_SELECTION # ?'
559
577
  $log.debug "insdie next selection"
@@ -568,9 +586,10 @@ module RubyCurses
568
586
  when @KEY_CLEAR_SELECTION
569
587
  clear_selection #if @select_mode == 'multiple'
570
588
  @repaint_required = true
571
- when 27, ?\C-c:
589
+ when 27, ?\C-c.getbyte(0)
572
590
  editing_canceled @current_index if @cell_editing_allowed
573
591
  cancel_block # block
592
+ @multiplier = 0
574
593
  when @KEY_ASK_FIND_FORWARD
575
594
  # ask_search_forward
576
595
  when @KEY_ASK_FIND_BACKWARD
@@ -585,6 +604,13 @@ module RubyCurses
585
604
  find_more
586
605
  when @KEY_BLOCK_SELECTOR
587
606
  mark_block #selection
607
+ when ?\C-u.getbyte(0)
608
+ # multiplier. Series is 4 16 64
609
+ @multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
610
+ return 0
611
+ when ?\C-c.getbyte(0)
612
+ @multiplier = 0
613
+ return 0
588
614
  else
589
615
  # this has to be fixed, if compo does not handle key it has to continue into next part FIXME
590
616
  ret = :UNHANDLED # changed on 2009-01-27 13:14 not going into unhandled, tab not released
@@ -599,15 +625,37 @@ module RubyCurses
599
625
  end
600
626
  end
601
627
  if ret == :UNHANDLED
602
- case ch
603
- when ?A..?Z, ?a..?z
604
- ret = set_selection_for_char ch.chr
628
+ if @one_key_selection
629
+ case ch
630
+ when ?A.getbyte(0)..?Z.getbyte(0), ?a.getbyte(0)..?z.getbyte(0), ?0.getbyte(0)..?9.getbyte(0)
631
+ # simple motion, key press defines motion
632
+ ret = set_selection_for_char ch.chr
633
+ else
634
+ ret = process_key ch, self
635
+ @multiplier = 0
636
+ return :UNHANDLED if ret == :UNHANDLED
637
+ end
605
638
  else
639
+ # no motion on single key, we can freak out like in vim, pref f <char> for set_selection
640
+ case ch
641
+ when ?0.getbyte(0)..?9.getbyte(0)
642
+ @multiplier *= 10 ; @multiplier += (ch-48)
643
+ return 0
644
+ end
606
645
  ret = process_key ch, self
646
+ @multiplier = 0
607
647
  return :UNHANDLED if ret == :UNHANDLED
608
648
  end
609
649
  end
610
650
  end
651
+ @multiplier = 0
652
+ end
653
+ def ask_selection_for_char
654
+ ch = @graphic.getch
655
+ if ch < 0 || ch > 255
656
+ return :UNHANDLED
657
+ end
658
+ ret = set_selection_for_char ch.chr
611
659
  end
612
660
  def ask_search_forward
613
661
  regex = get_string("Enter regex to search")
@@ -684,6 +732,12 @@ module RubyCurses
684
732
  # unfortunately 2009-01-11 19:47 combo boxes editable allows changing value
685
733
  editor.prepare_editor self, row, col, value
686
734
  editor.component.curpos = 0 # reset it after search, if user scrols down
735
+ #editor.component.graphic = @graphic # 2010-01-05 00:36 TRYING OUT BUFFERED
736
+ ## override is required if the listbox uses a buffer
737
+ if @should_create_buffer
738
+ $log.debug " overriding editors comp with GRAPHIC #{@graphic} "
739
+ editor.component.override_graphic(@graphic) # 2010-01-05 00:36 TRYING OUT BUFFERED
740
+ end
687
741
  set_form_col 0 #@left_margin
688
742
 
689
743
  # set original value so we can cancel
@@ -701,6 +755,7 @@ module RubyCurses
701
755
  if @cell_editing_allowed
702
756
  if !@cell_editor.nil?
703
757
  # $log.debug " cell editor (leave) setting value row: #{arow} val: #{@cell_editor.getvalue}"
758
+ $log.debug " cell editor #{@cell_editor.component.form.window} (leave) setting value row: #{arow} val: #{@cell_editor.getvalue}"
704
759
  @list[arow] = @cell_editor.getvalue #.dup 2009-01-10 21:42 boolean can't duplicate
705
760
  else
706
761
  $log.debug "CELL EDITOR WAS NIL, #{arow} "
@@ -744,7 +799,18 @@ module RubyCurses
744
799
  # processing. also, it pans the data horizontally giving the renderer
745
800
  # a section of it.
746
801
  def repaint
802
+ safe_create_buffer # 2010-01-04 12:36 BUFFERED moved here 2010-01-05 18:07
747
803
  return unless @repaint_required
804
+ # not sure where to put this, once for all or repeat 2010-02-17 23:07 RFED16
805
+ my_win = @form ? @form.window : @target_window
806
+ @graphic = my_win unless @graphic
807
+ #$log.warn "neither form not target window given!!! TV paint 368" unless my_win
808
+ raise " #{@name} neither form, nor target window given TV paint " unless my_win
809
+ raise " #{@name} NO GRAPHIC set as yet TV paint " unless @graphic
810
+ @win_left = my_win.left
811
+ @win_top = my_win.top
812
+
813
+ $log.debug " rlistbox repaint graphic #{@graphic} "
748
814
  print_borders if @to_print_borders == 1 # do this once only, unless everything changes
749
815
  rc = row_count
750
816
  maxlen = @maxlen ||= @width-2
@@ -783,20 +849,20 @@ module RubyCurses
783
849
  else
784
850
  selection_symbol = @row_unselected_symbol
785
851
  end
786
- @form.window.printstring r+hh, c, selection_symbol, acolor,@attr
852
+ @graphic.printstring r+hh, c, selection_symbol, acolor,@attr
787
853
  end
788
854
  #renderer = get_default_cell_renderer_for_class content.class.to_s
789
855
  renderer = cell_renderer()
790
856
  #renderer.show_selector @show_selector
791
857
  #renderer.row_selected_symbol @row_selected_symbol
792
858
  #renderer.left_margin @left_margin
793
- #renderer.repaint @form.window, r+hh, c+(colix*11), content, focussed, selected
859
+ #renderer.repaint @graphic, r+hh, c+(colix*11), content, focussed, selected
794
860
  ## added crow on 2009-02-06 23:03
795
861
  # since data is being truncated and renderer may need index
796
- renderer.repaint @form.window, r+hh, c+@left_margin, crow, content, focussed, selected
862
+ renderer.repaint @graphic, r+hh, c+@left_margin, crow, content, focussed, selected
797
863
  else
798
864
  # clear rows
799
- @form.window.printstring r+hh, c, " " * (@width-2), acolor,@attr
865
+ @graphic.printstring r+hh, c, " " * (@width-2), acolor,@attr
800
866
  end
801
867
  end
802
868
  if @cell_editing_allowed
@@ -804,6 +870,8 @@ module RubyCurses
804
870
  end
805
871
  @table_changed = false
806
872
  @repaint_required = false
873
+ @buffer_modified = true # required by form to call buffer_to_screen BUFFERED
874
+ buffer_to_window # RFED16 2010-02-17 23:16
807
875
  end
808
876
  def list_data_changed
809
877
  if row_count == 0 # added on 2009-02-02 17:13 so cursor not hanging on last row which could be empty
@@ -813,9 +881,27 @@ module RubyCurses
813
881
  end
814
882
  @repaint_required = true
815
883
  end
816
- def set_form_col col=0
817
- super col+@left_margin
818
- end
884
+ def set_form_col col1=0
885
+ # TODO BUFFERED use setrowcol @form.row, col
886
+ # TODO BUFFERED use cols_panned
887
+ @cols_panned ||= 0 # RFED16 2010-02-17 23:40
888
+ # editable listboxes will involve changing cursor and the form issue
889
+ ## added win_col on 2010-01-04 23:28 for embedded forms BUFFERED TRYING OUT
890
+ #win_col=@form.window.left
891
+ win_col = 0 # 2010-02-17 23:19 RFED16
892
+ #col = win_col + @orig_col + @col_offset + @curpos + @form.cols_panned
893
+ col2 = win_col + @col + @col_offset + col1 + @cols_panned + @left_margin
894
+ $log.debug " set_form_col in rlistbox #{@col}+ left_margin #{@left_margin} ( #{col2} ) "
895
+ #super col+@left_margin
896
+ #@form.setrowcol @form.row, col2 # added 2009-12-29 18:50 BUFFERED
897
+ setrowcol nil, col2 # 2010-02-17 23:19 RFED16
898
+ end
899
+ #def rowcol
900
+ ## $log.debug "rlistbox rowcol : #{@row+@row_offset+@winrow}, #{@col+@col_offset}"
901
+ #win_col=@form.window.left
902
+ #col2 = win_col + @col + @col_offset + @form.cols_panned + @left_margin
903
+ #return @row+@row_offset, col2
904
+ #end
819
905
  # experimental selection of multiple rows via block
820
906
  # specify a block start and then a block end
821
907
  # usage: bind mark_selection to a key. It works as a toggle.
@@ -851,7 +937,31 @@ module RubyCurses
851
937
  add_row_selection_interval(lower, higher)
852
938
  @repaint_required = true
853
939
  end
940
+ # 2010-02-18 11:40
941
+ # TRYING OUT - canceling editing if resized otherwise drawing errors can occur
942
+ # the earlier painted edited comp in yellow keeps showing until a key is pressed
854
943
 
944
+ def set_buffering params
945
+ super
946
+ ## Ensuring that changes to top get reflect in editing comp
947
+ #+ otherwise it raises an exception. Still the earlier cell_edit is being
948
+ #+ printed where it was , until a key is moved
949
+ # FIXME - do same for col
950
+ if @cell_editor
951
+ r,c = rowcol
952
+ if @cell_editor.component.row < @row_offset + @buffer_params[:screen_top]
953
+ @cell_editor.component.row = @row_offset + @buffer_params[:screen_top]
954
+ end
955
+ # TODO next block to be tested by placing a listbox in right split of vertical
956
+ if @cell_editor.component.col < @col_offset + @buffer_params[:screen_left]
957
+ @cell_editor.component.col = @col_offset + @buffer_params[:screen_left]
958
+ end
959
+ #editing_canceled @current_index if @cell_editing_allowed and @cell_editor
960
+ end
961
+ #set_form_row
962
+ @repaint_required = true
963
+ end
964
+
855
965
 
856
966
  # ADD HERE
857
967
  end # class listb
@@ -112,13 +112,13 @@ module RubyCurses
112
112
  when "ok_cancel" #, "input", "list", "field_list"
113
113
  make_buttons %w[&OK &Cancel]
114
114
  # experience 2009-02-22 12:52 trapping y and n - hopefully wont cause an edit problem
115
- @form.bind_key(?o){ press(?\M-o) }
116
- @form.bind_key(?c){ press(?\M-c) }
115
+ @form.bind_key(?o){ press(?\M-o) } # called method takes care of getbyte 1.9
116
+ @form.bind_key(?c){ press(?\M-c) } # called method takes care of getbyte 1.9
117
117
  when "yes_no"
118
118
  make_buttons %w[&Yes &No]
119
119
  # experience 2009-02-22 12:52 trapping y and n - hopefully wont cause an edit problem
120
- @form.bind_key(?y){ press(?\M-y) }
121
- @form.bind_key(?n){ press(?\M-n) }
120
+ @form.bind_key(?y){ press(?\M-y) } # called method takes care of getbyte 1.9
121
+ @form.bind_key(?n){ press(?\M-n) } # called method takes care of getbyte 1.9
122
122
  when "yes_no_cancel"
123
123
  make_buttons ["&Yes", "&No", "&Cancel"]
124
124
  when "custom"
@@ -176,10 +176,11 @@ module RubyCurses
176
176
  return @selected_index
177
177
  end
178
178
  def press ch
179
+ ch = ch.getbyte(0) if ch.class==String ## 1.9
179
180
  case ch
180
181
  when -1
181
182
  return
182
- when KEY_F1, 27, ?\C-q
183
+ when KEY_F1, 27, ?\C-q.getbyte(0)
183
184
  @selected_index = -1
184
185
  @stop = true
185
186
  return
@@ -238,6 +239,7 @@ module RubyCurses
238
239
  def print_message message=@message, row=nil
239
240
  @message_row = @message_col = 2
240
241
  display_length = @layout[:width]-8
242
+ $log.debug " print_message: dl:#{display_length} "
241
243
  # XXX this needs to go up and decide height of window
242
244
  if @message_height.nil?
243
245
  @message_height = (message.length/display_length)+1
@@ -258,10 +260,13 @@ module RubyCurses
258
260
  @message_col = (width-message.length)/2
259
261
  end
260
262
  @message_row = row
263
+ # added 2009-11-05 14:53 to fix erasure of border
264
+ display_length -= @message_col
261
265
  # FIXME : wont print if newline at end of message !!!
262
266
  #@window.printstring( row, @message_col , message, color=$reversecolor)
263
267
  # 2008-12-30 19:45 experimenting with label so we can get justify and wrapping.
264
268
  #@window.printstring( row, @message_col , message, color=$reversecolor)
269
+ $log.debug " print_message: row #{row}, col #{@message_col} "
265
270
  message_label = RubyCurses::Label.new @form, {'text' => message, "name"=>"message_label","row" => row, "col" => @message_col, "display_length" => display_length, "height" => @message_height, "attr"=>"reverse"}
266
271
 
267
272
  end
@@ -0,0 +1,325 @@
1
+ =begin
2
+ * Name: MultiContainer
3
+ * Description View (cycle) multiple components in one container using a key or menu
4
+ * Author: rkumar (arunachalesha)
5
+ * file created 2010-03-15 10:40
6
+ --------
7
+ * License:
8
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
9
+
10
+ =end
11
+ require 'rubygems'
12
+ require 'ncurses'
13
+ require 'logger'
14
+ require 'rbcurse'
15
+
16
+ include Ncurses
17
+ include RubyCurses
18
+ module RubyCurses
19
+ extend self
20
+
21
+ ##
22
+ # Extends TextView with ability to load more than one file or content
23
+ # and switch between files (buffers).
24
+ # NOTE: ideally, i should be able to dynamically add this functionality to either Textview
25
+ # or TextArea or even ListBox or Table someday. Should then be a Module rather than a class.
26
+ class MultiContainer < Widget
27
+ dsl_accessor :title
28
+ #include ListScrollable
29
+
30
+ def initialize form = nil, config={}, &block
31
+ @focusable = true
32
+ @row_offset = @col_offset = 1
33
+ super
34
+ @bmanager = BufferManager.new self
35
+ init_vars
36
+
37
+ end
38
+ def init_vars
39
+ super
40
+ bind_key(?\M-:, :buffer_menu)
41
+ # bind_key([?\C-x, ?f], :file_edit)
42
+ bind_key([?\C-x, ?k], :buffer_delete)
43
+ bind_key([?\C-x, ?\C-b], :buffers_list)
44
+ # easily cycle using p. n is used for next search.
45
+ #bind_key(?p, :buffer_previous)
46
+ @suppress_borders = false
47
+ @repaint_all = true
48
+ @name ||= "multicontainer"
49
+ end
50
+ ## returns current buffer
51
+ # @return [RBuffer] current buffer
52
+ def current_buffer
53
+ @bmanager.current
54
+ end
55
+ ##
56
+ # multi-container
57
+ def handle_key ch
58
+ $log.debug " MULTI handlekey #{ch}, #{@current_component} "
59
+ ret = :UNHANDLED
60
+ return :UNHANDLED unless @current_component
61
+ ret = @current_component.handle_key(ch)
62
+ $log.debug " MULTI = comp returned #{ret} "
63
+ if ret == :UNHANDLED
64
+ # check for bindings, these cannot override above keys since placed at end
65
+ begin
66
+ ret = process_key ch, self
67
+ $log.debug " MULTI = process_key returned #{ret} "
68
+ rescue => err
69
+ $error_message = err
70
+ @form.window.print_error_message
71
+ $log.error " Multicomponent process_key #{err} "
72
+ $log.debug(err.backtrace.join("\n"))
73
+ end
74
+ return :UNHANDLED if ret == :UNHANDLED
75
+ end
76
+ # check for any keys not handled and check our own ones
77
+ return ret #
78
+ end
79
+ def repaint
80
+ print_border if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
81
+ return unless @current_component
82
+ $log.debug " MULTI REPAINT "
83
+ ret = @current_component.repaint
84
+ end
85
+ def print_border
86
+ $log.debug " #{@name} print_borders, #{@graphic.name} "
87
+ color = $datacolor
88
+ @graphic.print_border_only @row, @col, @height-1, @width, color #, Ncurses::A_REVERSE
89
+ print_title
90
+ end
91
+ def print_title
92
+ $log.debug " print_title #{@row}, #{@col}, #{@width} "
93
+ @graphic.printstring( @row, @col+(@width-@title.length)/2, @title, $datacolor, @title_attrib) unless @title.nil?
94
+ end
95
+ # this is just a test of the simple "most" menu
96
+ # can use this for next, prev, first, last, new, delete, overwrite etc
97
+ def buffer_menu
98
+ menu = PromptMenu.new self
99
+ menu.add(menu.create_mitem( 'l', "list buffers", "list buffers ", :buffers_list ))
100
+ item = menu.create_mitem( 'b', "Buffer Options", "Buffer Options" )
101
+ menu1 = PromptMenu.new( self, "Buffer Options")
102
+ menu1.add(menu1.create_mitem( 'n', "Next", "Switched to next buffer", :buffer_next ))
103
+ menu1.add(menu1.create_mitem( 'p', "Prev", "Switched to previous buffer", :buffer_previous ))
104
+ menu1.add(menu1.create_mitem( 'f', "First", "Switched to first buffer", :buffer_first ))
105
+ menu1.add(menu1.create_mitem( 'l', "Last", "Switched to last buffer", :buffer_last ))
106
+ menu1.add(menu1.create_mitem( 'd', "Delete", "Deleted buffer", :buffer_delete ))
107
+ item.action = menu1
108
+ menu.add(item)
109
+ # how do i know what's available. the application or window should know where to place
110
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor #, menu
111
+ end
112
+
113
+ #%w[next previous first last].each do |pos|
114
+ #eval(
115
+ #"def _buffer_#{pos}
116
+ #@current_buffer = @bmanager.#{pos}
117
+ #set_current_buffer
118
+ #end"
119
+ #)
120
+ #end
121
+
122
+ def buffer_next
123
+ perror "No other buffer" and return if @bmanager.size < 2
124
+
125
+ @current_buffer = @bmanager.next
126
+ set_current_buffer
127
+ end
128
+ def buffer_previous
129
+ perror "No other buffer" and return if @bmanager.size < 2
130
+
131
+ @current_buffer = @bmanager.previous
132
+ $log.debug " buffer_prev got #{@current_buffer} "
133
+ set_current_buffer
134
+ end
135
+ def buffer_first
136
+ @current_buffer = @bmanager.first
137
+ $log.debug " buffer_first got #{@current_buffer} "
138
+ set_current_buffer
139
+ end
140
+ def buffer_last
141
+ @current_buffer = @bmanager.last
142
+ $log.debug " buffer_last got #{@current_buffer} "
143
+ set_current_buffer
144
+ end
145
+ def buffer_delete
146
+ if @bmanager.size > 1
147
+ @bmanager.delete_at
148
+ @current_buffer = @bmanager.previous
149
+ set_current_buffer
150
+ else
151
+ perror "Only one buffer. Cannot delete."
152
+ end
153
+ end
154
+
155
+ #%w[next previous first last].each do |pos|
156
+ #eval(
157
+ #"def _buffer_#{pos}
158
+ #@current_buffer = @bmanager.#{pos}
159
+ #set_current_buffer
160
+ #end"
161
+ #)
162
+ #end
163
+
164
+ def buffer_next
165
+ perror "No other buffer" and return if @bmanager.size < 2
166
+
167
+ @current_buffer = @bmanager.next
168
+ set_current_buffer
169
+ end
170
+ def buffer_previous
171
+ perror "No other buffer" and return if @bmanager.size < 2
172
+
173
+ @current_buffer = @bmanager.previous
174
+ $log.debug " buffer_prev got #{@current_buffer} "
175
+ set_current_buffer
176
+ end
177
+ def buffer_first
178
+ @current_buffer = @bmanager.first
179
+ $log.debug " buffer_first got #{@current_buffer} "
180
+ set_current_buffer
181
+ end
182
+ def buffer_last
183
+ @current_buffer = @bmanager.last
184
+ $log.debug " buffer_last got #{@current_buffer} "
185
+ set_current_buffer
186
+ end
187
+ def buffer_delete
188
+ if @bmanager.size > 1
189
+ @bmanager.delete_at
190
+ @current_buffer = @bmanager.previous
191
+ set_current_buffer
192
+ else
193
+ perror "Only one buffer. Cannot delete."
194
+ end
195
+ end
196
+ def buffer_at index
197
+ @current_buffer = @bmanager.element_at index
198
+ $log.debug " buffer_last got #{@current_buffer} "
199
+ set_current_buffer
200
+ end
201
+ ##
202
+ # Add a component with a title
203
+ # @param [Widget] component
204
+ # @param [String] title
205
+ def add component, title
206
+ component.row = @row+@row_offset+1
207
+ component.col = @col+@col_offset+1
208
+ component.width = @width-2
209
+ component.height = @height-2
210
+ component.form = @form
211
+ component.override_graphic(@graphic)
212
+ @current_buffer = @bmanager.add component, title
213
+ set_current_buffer
214
+ $log.debug " ADD got cb : #{@current_buffer} "
215
+ end
216
+ def set_current_buffer
217
+ @current_component = @current_buffer.component
218
+ @current_title = @current_buffer.title
219
+ @current_component.repaint_all true
220
+ end
221
+ def perror errmess=$error_message
222
+ @form.window.print_error_message errmess
223
+ end
224
+ def buffers_list
225
+ $log.debug " TODO buffers_list: #{@bmanager.size} "
226
+ menu = PromptMenu.new self
227
+ @bmanager.each_with_index{ |b, ix|
228
+ aproc = Proc.new { buffer_at(ix) }
229
+ name = b.title
230
+ num = ix + 1
231
+ menu.add(menu.create_mitem( num.to_s, name, "Switched to buffer #{ix}", aproc ))
232
+ }
233
+ menu.display @form.window, $error_message_row, $error_message_col, $datacolor
234
+ end
235
+ # required otherwise some components may not get correct cursor position on entry
236
+ # e.g. table
237
+ def on_enter
238
+ set_form_row
239
+ end
240
+ def set_form_row
241
+ if !@current_component.nil?
242
+ $log.debug " #{@name} set_form_row calling sfr for #{@current_component.name} "
243
+ @current_component.set_form_row
244
+ @current_component.set_form_col
245
+ end
246
+ end
247
+ end # class multitextview
248
+ ##
249
+ # Handles multiple buffers, navigation, maintenance etc
250
+ # Instantiated at startup of MultiTextView
251
+ #
252
+ class BufferManager
253
+ include Enumerable
254
+ def initialize source
255
+ @source = source
256
+ @buffers = [] # contains RBuffer
257
+ @counter = 0
258
+ # for each buffer i need to store data, current_index (row), curpos (col offset) and title (filename).
259
+ end
260
+ def element_at index
261
+ @buffers[index]
262
+ end
263
+ def each
264
+ @buffers.each {|k| yield(k)}
265
+ end
266
+
267
+ ##
268
+ # @return [RBuffer] current buffer/file
269
+ ##
270
+ def current
271
+ @buffers[@counter]
272
+ end
273
+ ##
274
+ # Would have liked to just return next buffer and not get lost in details of caller
275
+ #
276
+ # @return [RBuffer] next buffer/file
277
+ ##
278
+ def next
279
+ @counter += 1
280
+ @counter = 0 if @counter >= @buffers.size
281
+ @buffers[@counter]
282
+ end
283
+ ##
284
+ # @return [RBuffer] previous buffer/file
285
+ ##
286
+ def previous
287
+ $log.debug " previous bs: #{@buffers.size}, #{@counter} "
288
+ @counter -= 1
289
+ return last() if @counter < 0
290
+ $log.debug " previous ctr #{@counter} "
291
+ @buffers[@counter]
292
+ end
293
+ def first
294
+ @counter = 0
295
+ @buffers[@counter]
296
+ end
297
+ def last
298
+ @counter = @buffers.size - 1
299
+ @buffers[@counter]
300
+ end
301
+ ##
302
+ def delete_at index=@counter
303
+ @buffers.delete_at index
304
+ end
305
+ def delete_by_name name
306
+ @buffers.delete_if {|b| b.filename == name }
307
+ end
308
+ def insert component, position, title=nil
309
+ anew = RComponents.new(component, title)
310
+ @buffers.insert position, anew
311
+ @counter = position
312
+ return anew
313
+ end
314
+ def add component, title=nil
315
+ $log.debug " ADD H: #{component.height} C: #{component.width} "
316
+ insert component, @buffers.size, title
317
+ end
318
+ def size
319
+ @buffers.size
320
+ end
321
+ alias :count :size
322
+ end
323
+ RComponents = Struct.new(:component, :title)
324
+
325
+ end # modul