rbcurse 1.1.5 → 1.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/CHANGELOG +45 -0
  2. data/Makefile +1 -1
  3. data/Manifest.txt +91 -0
  4. data/NOTES +349 -2
  5. data/README.markdown +12 -0
  6. data/VERSION +1 -1
  7. data/examples/abasiclist.rb +25 -0
  8. data/examples/alpmenu.rb +42 -0
  9. data/examples/app.rb +883 -0
  10. data/examples/appcombo.rb +17 -0
  11. data/examples/appdirtree.rb +73 -0
  12. data/examples/appemail.rb +164 -0
  13. data/examples/appemaillb.rb +308 -0
  14. data/examples/appgcompose.rb +303 -0
  15. data/examples/appgmail.rb +951 -0
  16. data/examples/atree.rb +56 -0
  17. data/examples/dirtree.rb +78 -0
  18. data/examples/focusmanager.rb +31 -0
  19. data/examples/imap.rb +48 -0
  20. data/examples/menu1.rb +79 -0
  21. data/examples/multispl.rb +86 -0
  22. data/examples/rfe.rb +3 -4
  23. data/examples/rmail.rb +188 -0
  24. data/examples/s.rb +10 -0
  25. data/examples/scrollbar.rb +104 -0
  26. data/examples/splitp.rb +56 -0
  27. data/examples/table1.rb +30 -0
  28. data/examples/term.rb +48 -0
  29. data/examples/term2.rb +54 -0
  30. data/examples/test1.rb +4 -2
  31. data/examples/test2.rb +9 -9
  32. data/examples/testapp.rb +44 -0
  33. data/examples/testapp2.rb +51 -0
  34. data/examples/testcombo.rb +2 -2
  35. data/examples/testgmail.rb +46 -0
  36. data/examples/testlistbox.rb +0 -1
  37. data/examples/testmultispl.rb +199 -0
  38. data/examples/testree.rb +127 -0
  39. data/examples/testscroller.rb +0 -1
  40. data/examples/testscrolllb.rb +1 -1
  41. data/examples/testscrollp.rb +2 -1
  42. data/examples/testscrollta.rb +1 -1
  43. data/examples/testscrolltable.rb +1 -2
  44. data/examples/testsplit.rb +1 -1
  45. data/examples/testsplit2.rb +1 -1
  46. data/examples/testsplit3.rb +1 -1
  47. data/examples/testsplit3_1.rb +1 -1
  48. data/examples/testsplit3a.rb +1 -1
  49. data/examples/testsplit3b.rb +1 -1
  50. data/examples/testsplitta.rb +1 -1
  51. data/examples/testsplittv.rb +1 -1
  52. data/examples/testsplittvv.rb +1 -1
  53. data/examples/testtodo.rb +491 -488
  54. data/examples/testvimsplit.rb +111 -0
  55. data/examples/todo.db +0 -0
  56. data/examples/todocsv.csv +28 -0
  57. data/examples/viewtodo.rb +408 -403
  58. data/lib/rbcurse/action.rb +1 -0
  59. data/lib/rbcurse/app.rb +1294 -0
  60. data/lib/rbcurse/applicationheader.rb +7 -2
  61. data/lib/rbcurse/checkboxcellrenderer.rb +0 -12
  62. data/lib/rbcurse/colormap.rb +34 -8
  63. data/lib/rbcurse/comboboxcellrenderer.rb +0 -11
  64. data/lib/rbcurse/defaultlistselectionmodel.rb +23 -7
  65. data/lib/rbcurse/extras/bottomline.rb +1681 -0
  66. data/lib/rbcurse/extras/directorylist.rb +445 -0
  67. data/lib/rbcurse/extras/directorytree.rb +69 -0
  68. data/lib/rbcurse/extras/divider.rb +310 -0
  69. data/lib/rbcurse/extras/focusmanager.rb +31 -0
  70. data/lib/rbcurse/extras/listselectable.rb +222 -0
  71. data/lib/rbcurse/extras/masterdetail.rb +164 -0
  72. data/lib/rbcurse/extras/menutree.rb +63 -0
  73. data/lib/rbcurse/extras/rlink.rb +27 -0
  74. data/lib/rbcurse/extras/rmenulink.rb +21 -0
  75. data/lib/rbcurse/extras/scrollbar.rb +134 -0
  76. data/lib/rbcurse/extras/stdscrwindow.rb +247 -0
  77. data/lib/rbcurse/extras/tabular.rb +258 -0
  78. data/lib/rbcurse/extras/tabularwidget.rb +1070 -0
  79. data/lib/rbcurse/extras/viewer.rb +106 -0
  80. data/lib/rbcurse/io.rb +137 -80
  81. data/lib/rbcurse/keylabelprinter.rb +4 -0
  82. data/lib/rbcurse/listcellrenderer.rb +91 -59
  83. data/lib/rbcurse/listscrollable.rb +93 -95
  84. data/lib/rbcurse/listselectable.rb +60 -7
  85. data/lib/rbcurse/ractionevent.rb +67 -0
  86. data/lib/rbcurse/rbasiclistbox.rb +688 -0
  87. data/lib/rbcurse/rcombo.rb +5 -5
  88. data/lib/rbcurse/rcommandwindow.rb +555 -0
  89. data/lib/rbcurse/rinputdataevent.rb +12 -0
  90. data/lib/rbcurse/rlistbox.rb +305 -124
  91. data/lib/rbcurse/rmenu.rb +99 -46
  92. data/lib/rbcurse/rmessagebox.rb +13 -6
  93. data/lib/rbcurse/rmulticontainer.rb +54 -93
  94. data/lib/rbcurse/rmultisplit.rb +731 -0
  95. data/lib/rbcurse/rmultitextview.rb +3 -2
  96. data/lib/rbcurse/rpopupmenu.rb +0 -1
  97. data/lib/rbcurse/rprogress.rb +117 -0
  98. data/lib/rbcurse/rscrollpane.rb +2 -1
  99. data/lib/rbcurse/rsplitpane.rb +94 -20
  100. data/lib/rbcurse/rsplitpane2.rb +1009 -0
  101. data/lib/rbcurse/rtabbedpane.rb +3 -2
  102. data/lib/rbcurse/rtabbedwindow.rb +0 -1
  103. data/lib/rbcurse/rtable.rb +92 -64
  104. data/lib/rbcurse/rtextarea.rb +91 -57
  105. data/lib/rbcurse/rtextview.rb +223 -70
  106. data/lib/rbcurse/rtree.rb +723 -0
  107. data/lib/rbcurse/rviewport.rb +2 -1
  108. data/lib/rbcurse/rvimsplit.rb +768 -0
  109. data/lib/rbcurse/rwidget.rb +524 -325
  110. data/lib/rbcurse/table/tablecellrenderer.rb +1 -1
  111. data/lib/rbcurse/table/tabledatecellrenderer.rb +0 -1
  112. data/lib/rbcurse/tree/treecellrenderer.rb +137 -0
  113. data/lib/rbcurse/tree/treemodel.rb +428 -0
  114. data/lib/rbcurse/vieditable.rb +14 -13
  115. data/lib/ver/ncurses.rb +6 -0
  116. data/lib/ver/window.rb +67 -32
  117. metadata +99 -23
  118. data/bin/rbcurse +0 -0
  119. data/examples/rvimsplit.rb +0 -376
  120. data/examples/todo.rb +0 -1
  121. data/lib/rbcurse/rform.rb +0 -845
  122. data/lib/rbcurse/selectable.rb +0 -94
  123. data/rbcurse.gemspec +0 -188
@@ -0,0 +1,164 @@
1
+ require 'rbcurse/rvimsplit'
2
+ require 'forwardable'
3
+ # A convenience class that implements a 3 way Master Detail like form
4
+ # as in some email clients. See appemail.rb for usage.
5
+ # You may use this class or extend it. It takes care of expanding,
6
+ # increasing etc the 3 splits.
7
+ # This class is not fully tested beyond appemail.rb, and can change
8
+ # quite a bit. Users may want to copy this to prevent from major changes
9
+ # that could take place.
10
+ class MasterDetail < Widget
11
+ dsl_property :weight
12
+ attr_reader :vim # the vimsplit for any further configuration such as min_weight etc
13
+ extend Forwardable
14
+ def_delegators :@vim, :on_enter, :on_leave, :handle_key, :current_component
15
+ def initialize form, config={}, &block
16
+ @focusable = true
17
+ @height = Ncurses.LINES-2
18
+ @weight = 0.25
19
+ super
20
+ _create_vimsplit
21
+ init_vars
22
+ end
23
+ def init_vars #:nodoc:
24
+ @first_time = true
25
+ @repaint_required = true
26
+ end
27
+ def repaint
28
+ if @first_time
29
+ @first_time = nil
30
+ [@vim, @left, @right1, @right2].each { |e|
31
+ e.set_buffering(:target_window => @target_window || @form.window, :form => @form)
32
+ }
33
+ end
34
+ @vim.repaint
35
+ end
36
+ # set the single component on the left side/pane, typically a +Listbox+.
37
+ # If an array is passed, the Listbox created is returned for further
38
+ # manipulation.
39
+ # @param [Widget] component to set on left
40
+ # @return [Widget] component added
41
+ def set_left_component comp, weight=nil
42
+ @left = @vim.add comp, :FIRST, weight
43
+ _add_component comp
44
+ @left
45
+ end
46
+ # set the first component on the right side/pane, typically a +Listbox+.
47
+ # @param [Widget] component to set on right
48
+ # @return [Widget] component added
49
+ def set_right_top_component comp, weight=0.5
50
+ @added_top = true
51
+ @right1 = @vim.add comp, :SECOND, weight
52
+ _add_component comp
53
+ @right1
54
+ end
55
+ # set the second component on the right side/pane, typically a
56
+ # +TextView+
57
+ # @param [Widget] component to set on right
58
+ # @return [Widget] component added
59
+ def set_right_bottom_component comp, weight=nil
60
+ raise "Please add top component first!" unless @added_top
61
+ # what if user gives in wrong order !!
62
+ @gb = @vim.add :divider, :SECOND, 0
63
+ @right2 = @vim.add comp, :SECOND, weight
64
+ @gb.next(@right2)
65
+ _add_component comp
66
+ @right2
67
+ end
68
+ def focus comp
69
+ case comp
70
+ when :left
71
+ @vim.goto_component @left
72
+ when :top_right
73
+ @vim.goto_component @right1
74
+ when :bottom_right
75
+ @vim.goto_component @right2
76
+ else
77
+ @vim.goto_component comp
78
+ end
79
+ end
80
+ private
81
+ # does nothing at present
82
+ def _add_component comp #:nodoc:
83
+ end
84
+ # creates a Vimplit containing 3 panes. Sets events in order to
85
+ # increase and decrease panes/windows.
86
+ def _create_vimsplit #:nodoc:
87
+ @vim = VimSplit.new nil, :row => @row, :col => @col, :width => @width, :height => @height, :weight => @weight, :orientation => :VERTICAL, :suppress_borders => true do |s|
88
+ s.parent_component = self
89
+ #s.target_window = @form.window
90
+ #s.add @left, :FIRST
91
+ #s.add @right1, :SECOND
92
+ #s.add @right2, :SECOND
93
+ s.bind :COMPONENT_RESIZE_EVENT do |e|
94
+ #alert "got a resize event #{e.type} "
95
+ case e.type
96
+ when :INCREASE
97
+ case e.source
98
+ when @right2
99
+ increase_body
100
+ when @right1
101
+ increase_headers
102
+ when @left
103
+
104
+ end
105
+ when :DECREASE
106
+ case e.source
107
+ when @right2
108
+ increase_headers
109
+ when @right1
110
+ increase_body
111
+ when @left
112
+ @left.width -= 1
113
+ @right2.col -=1
114
+ @right1.col -=1
115
+ @right1.width +=1
116
+ @right2.width +=1
117
+ @right2.repaint_required true
118
+ @right1.repaint_required true
119
+ @left.repaint_required true
120
+ end
121
+ when :EXPAND
122
+ case e.source
123
+ when @right2
124
+ h = 3
125
+ @right2.row(@right1.row + h)
126
+ oldh = @right1.height
127
+ @right1.height = h
128
+ @right1.current_index = 0
129
+ @right2.height += (oldh - h)
130
+ @right2.repaint_required true
131
+ @right1.repaint_required true
132
+ when @right1
133
+ h = 3
134
+ @right2.row(@right2.row + (@right2.height - 3))
135
+ oldh = @right2.height
136
+ @right2.height = h
137
+ #@right1.current_index = 0
138
+ @right1.height += (oldh - h)
139
+ @right2.repaint_required true
140
+ @right1.repaint_required true
141
+ end
142
+ end
143
+ end # bind
144
+ end
145
+ end # def
146
+ # increase the top right pane and reduces lower one
147
+ # TODO: to take into account multiplier
148
+ def increase_headers #:nodoc:
149
+ @right2.row @right2.row()+1
150
+ @right1.height +=1
151
+ @right2.height -=1
152
+ @right2.repaint_required true
153
+ @right1.repaint_required true
154
+ end
155
+ # decrease the top right pane and increase lower one
156
+ # TODO: to take into account multiplier
157
+ def increase_body #:nodoc:
158
+ @right2.row @right2.row()-1
159
+ @right1.height -=1
160
+ @right2.height +=1
161
+ @right2.repaint_required true
162
+ @right1.repaint_required true
163
+ end
164
+ end # class
@@ -0,0 +1,63 @@
1
+ module RubyCurses
2
+ # Create a simple tree-ish structure.
3
+ # Each node is not a tree, only submenus are trees
4
+ # Others contain a hash with menu character and code
5
+ # Typically the code is not a method symbol, it is to be
6
+ # used to decode a description or method symbol from anoterh hash
7
+ # @usage
8
+ # menu = MenuTree.new "Main", { c: :goprev, d: :gonext, e: :gonext, s: :submenu }
9
+ # menu.submenu :s, "submenu", {a: :next1, b: :next2, f: :next3 }
10
+ # puts menu.hash
11
+ # puts "each ..."
12
+ # menu.each { |e| puts e }
13
+ # menu.each_pair { |e, v| puts "#{e} #{v}" }
14
+ # puts " -- :c -- "
15
+ # puts menu[:c]
16
+ # puts " -- :s -- "
17
+ # puts menu[:s].children
18
+ class MenuTree
19
+ attr_reader :value
20
+ def initialize value, hash = {}
21
+ @value = [value, hash]
22
+ end
23
+ def << kv
24
+ @value[1][kv[0]] = kv[1]
25
+ end
26
+ def hash
27
+ @value[1]
28
+ end
29
+ alias :children :hash
30
+ def push hsh
31
+ hash().merge hsh
32
+ end
33
+ def [](x)
34
+ hash()[x]
35
+ end
36
+ def []=(x,y)
37
+ hash()[x] = y
38
+ end
39
+ def submenu key, value, hash = {}
40
+ m = MenuTree.new value, hash
41
+ #hash()[key] = [value, hash]
42
+ hash()[key] = m
43
+ end
44
+ def each
45
+ hash().keys.each { |e| yield e }
46
+ end
47
+ def each_pair
48
+ hash().each_pair { |name, val| yield name, val }
49
+ end
50
+ end
51
+ end
52
+ if __FILE__ == $PROGRAM_NAME
53
+ menu = RubyCurses::MenuTree.new "Main", { c: :goprev, d: :gonext, e: :gonext, s: :submenu }
54
+ menu.submenu :s, "submenu", {a: :next1, b: :next2, f: :next3 }
55
+ puts menu.hash
56
+ puts "each ..."
57
+ menu.each { |e| puts e }
58
+ menu.each_pair { |e, v| puts "#{e} #{v}" }
59
+ puts " -- :c -- "
60
+ puts menu[:c]
61
+ puts " -- :s -- "
62
+ puts menu[:s].children
63
+ end
@@ -0,0 +1,27 @@
1
+ require 'rbcurse'
2
+ ##
3
+ module RubyCurses
4
+ class Link < Button
5
+ dsl_property :description
6
+
7
+
8
+ def initialize form, config={}, &block
9
+ super
10
+ @text_offset = 0
11
+ # haha we've never done this, pin the cursor up on 0,0
12
+ @col_offset = -1
13
+ if @mnemonic
14
+ form.bind_key(@mnemonic.downcase, self){ self.fire }
15
+ end
16
+ @display_length = config[:width]
17
+ end
18
+ def fire
19
+ super
20
+ self.focus
21
+ end
22
+ def getvalue_for_paint
23
+ getvalue()
24
+ end
25
+ ##
26
+ end # class
27
+ end # module
@@ -0,0 +1,21 @@
1
+ require 'rbcurse/extras/rlink'
2
+ ##
3
+ module RubyCurses
4
+ class MenuLink < Link
5
+ dsl_property :description
6
+
7
+ def initialize form, config={}, &block
8
+ super
9
+ @col_offset = -1 * @col
10
+ @row_offset = -1 * @row
11
+ end
12
+ # added for some standardization 2010-09-07 20:28
13
+ # alias :text :getvalue # NEXT VERSION
14
+ # change existing text to label
15
+
16
+ def getvalue_for_paint
17
+ "%s %-12s - %-s" % [ @mnemonic , getvalue(), @description ]
18
+ end
19
+ ##
20
+ end # class
21
+ end # module
@@ -0,0 +1,134 @@
1
+ require 'rbcurse/app'
2
+ include Ncurses
3
+ include RubyCurses
4
+
5
+ # This paints a vertical white bar given row and col, and length. It also calculates and prints
6
+ # a small bar over this based on relaetd objects list.length and current_index.
7
+ # Typically, after setup one would keep updating only current_index from the repaint method
8
+ # of caller or in the traversal event. This would look best if the listbox also has a reverse video border, or none.
9
+ # @example
10
+ # lb = list_box ....
11
+ # sb = Scrollbar.new @form, :row => lb.row, :col => lb.col, :length => lb.height, :list_length => lb.row_count, :current_index => 0
12
+ # .... later as user traverses
13
+ # sb.current_index = lb.current_index
14
+ # sb = Scrollbar.new @form, :parent => list
15
+ #
16
+ # At a later stage, we will integrate this with lists and tables, so it will happen automatically.
17
+ #
18
+ # @since 1.2.0 UNTESTED
19
+ module RubyCurses
20
+ class Scrollbar < Widget
21
+ # row to start, same as listbox, required.
22
+ dsl_property :row
23
+ # column to start, same as listbox, required.
24
+ dsl_property :col
25
+ # how many rows is this (should be same as listboxes height, required.
26
+ dsl_property :length
27
+ # vertical or horizontal currently only VERTICAL
28
+ dsl_property :orientation
29
+ # initialize based on parent's values
30
+ dsl_property :parent
31
+ # which row is focussed, current_index of listbox, required.
32
+ dsl_property :current_index
33
+ # how many total rows of data does the list have, same as @list.length, required.
34
+ dsl_property :list_length
35
+
36
+ # TODO: if parent passed, we shold bind to ON_ENTER and get current_index, so no extra work is required.
37
+
38
+ def initialize form, config={}, &block
39
+
40
+ # setting default first or else Widget will place its BW default
41
+ #@color, @bgcolor = ColorMap.get_colors_for_pair $bottomcolor
42
+ super
43
+ @color_pair = get_color $datacolor, @color, @bgcolor
44
+ @scroll_pair = get_color $bottomcolor, :green, :white
45
+ @window = form.window
46
+ @editable = false
47
+ @focusable = false
48
+ @repaint_required = true
49
+ @orientation = :V
50
+ if @parent
51
+ @parent.bind :ENTER_ROW do |p|
52
+ # parent must implement row_count, and have a @current_index
53
+ raise StandardError, "Parent must implement row_count" unless p.respond_to? :row_count
54
+ self.current_index = p.current_index
55
+ @repaint_required = true #requred otherwise at end when same value sent, prop handler
56
+ # will not be fired (due to optimization).
57
+ end
58
+ end
59
+ end
60
+
61
+ ##
62
+ # repaint the scrollbar
63
+ # Taking the data from parent as late as possible in case parent resized, or
64
+ # moved around by a container.
65
+ def repaint
66
+ if @parent
67
+ @row = @parent.row+1
68
+ @col = @parent.col + @parent.width - 1
69
+ @length = @parent.height - 2
70
+ @list_length = @parent.row_count
71
+ @current_index ||= @parent.current_index
72
+ @border_attrib ||= @parent.border_attrib
73
+ end
74
+ raise ArgumentError, "current_index must be provided" unless @current_index
75
+ raise ArgumentError, "list_length must be provided" unless @list_length
76
+ my_win = @form ? @form.window : @target_window
77
+ @graphic = my_win unless @graphic
78
+ return unless @repaint_required
79
+
80
+ # first print a right side vertical line
81
+ #bc = $bottomcolor # dark blue
82
+ bc = $datacolor
83
+ bordercolor = @border_color || bc
84
+ borderatt = @border_attrib || Ncurses::A_REVERSE
85
+
86
+
87
+ @graphic.attron(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
88
+ $log.debug " XXX SCROLL #{@row} #{@col} #{@length} "
89
+ @graphic.mvvline(@row+0, @col, 1, @length-0)
90
+ @graphic.attroff(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
91
+
92
+ # now calculate and paint the scrollbar
93
+ pht = @length
94
+ listlen = @list_length * 1.0
95
+ @current_index = 0 if @current_index < 0
96
+ @current_index = listlen-1 if @current_index >= listlen
97
+ sclen = (pht/listlen)* @length
98
+ scloc = (@current_index/listlen)* @length
99
+ scloc = (@length - sclen) if scloc > @length - sclen # don't exceed end
100
+ if @current_index == @list_length - 1
101
+ scloc = @length - sclen + 1
102
+ end
103
+ @graphic.attron(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
104
+ r = @row + scloc
105
+ c = @col + 0
106
+ @graphic.mvvline(r, c, 1, sclen)
107
+ @graphic.attroff(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
108
+ @repaint_required = false
109
+ end
110
+ ##
111
+ ##
112
+ # ADD HERE
113
+ end
114
+ end
115
+ if __FILE__ == $PROGRAM_NAME
116
+ App.new do
117
+ r = 5
118
+ len = 20
119
+ list = []
120
+ 0.upto(100) { |v| list << "#{v} scrollable data" }
121
+ lb = list_box "A list", :list => list
122
+ #sb = Scrollbar.new @form, :row => r, :col => 20, :length => len, :list_length => 50, :current_index => 0
123
+ rb = Scrollbar.new @form, :parent => lb
124
+ #hline :width => 20, :row => len+r
125
+ #keypress do |ch|
126
+ #case ch
127
+ #when :down
128
+ #sb.current_index += 1
129
+ #when :up
130
+ #sb.current_index -= 1
131
+ #end
132
+ #end
133
+ end
134
+ end
@@ -0,0 +1,247 @@
1
+ require 'ver/ncurses'
2
+ module RubyCurses
3
+ #
4
+ # an attempt to make a window based on stdscr for bottom line printing so the entire
5
+ # application can have one pointer, regardless of whether through App
6
+ # or otherwise. This still provides the full getchar operation, copied from
7
+ # Window class which is the main purpose of this. So as to provide ask, agree and say.
8
+ #
9
+ # We should be able to pass this window to bottomline and have one global bottomline
10
+ # created once (by window class ?)
11
+ #
12
+ class StdscrWindow
13
+ attr_reader :width, :height, :top, :left
14
+
15
+ def initialize
16
+
17
+ @window = Ncurses.stdscr
18
+ $error_message_row ||= Ncurses.LINES-1
19
+ $error_message_col ||= 1
20
+ init_vars
21
+
22
+
23
+ end
24
+ def init_vars
25
+ Ncurses::keypad(@window, true)
26
+ @stack = []
27
+ end
28
+ ##
29
+
30
+ # Ncurses
31
+
32
+ def method_missing(meth, *args)
33
+ @window.send(meth, *args)
34
+ end
35
+
36
+ def print(string, width = width)
37
+ return unless visible?
38
+ @window.waddnstr(string.to_s, width)
39
+ end
40
+
41
+ def print_yx(string, y = 0, x = 0)
42
+ @window.mvwaddnstr(y, x, string, width)
43
+ end
44
+
45
+ def print_empty_line
46
+ return unless visible?
47
+ @window.printw(' ' * width)
48
+ end
49
+
50
+ def print_line(string)
51
+ print(string.ljust(width))
52
+ end
53
+
54
+ def puts(*strings)
55
+ print(strings.join("\n") << "\n")
56
+ end
57
+
58
+ def refresh
59
+ @window.refresh
60
+ end
61
+
62
+
63
+ def color=(color)
64
+ @color = color
65
+ @window.color_set(color, nil)
66
+ end
67
+
68
+ def highlight_line(color, y, x, max)
69
+ @window.mvchgat(y, x, max, Ncurses::A_NORMAL, color, nil)
70
+ end
71
+
72
+ def ungetch(ch)
73
+ Ncurses.ungetch(ch)
74
+ end
75
+
76
+ def getch
77
+ c = @window.getch
78
+ #if c == Ncurses::KEY_RESIZE
79
+ rescue Interrupt => ex
80
+ 3 # is C-c
81
+ end
82
+
83
+ # returns control, alt, alt+ctrl, alt+control+shift, F1 .. etc
84
+ # ALT combinations also send a 27 before the actual key
85
+ # Please test with above combinations before using on your terminal
86
+ # added by rkumar 2008-12-12 23:07
87
+ def getchar
88
+ while 1
89
+ ch = getch
90
+ #$log.debug "window getchar() GOT: #{ch}" if ch != -1
91
+ if ch == -1
92
+ # the returns escape 27 if no key followed it, so its SLOW if you want only esc
93
+ if @stack.first == 27
94
+ #$log.debug " -1 stack sizze #{@stack.size}: #{@stack.inspect}, ch #{ch}"
95
+ case @stack.size
96
+ when 1
97
+ @stack.clear
98
+ return 27
99
+ when 2 # basically a ALT-O, this will be really slow since it waits for -1
100
+ ch = 128 + @stack.last
101
+ @stack.clear
102
+ return ch
103
+ when 3
104
+ $log.debug " SHOULD NOT COME HERE getchar()"
105
+ end
106
+ end
107
+ @stack.clear
108
+ next
109
+ end
110
+ # this is the ALT combination
111
+ if @stack.first == 27
112
+ # experimental. 2 escapes in quick succession to make exit faster
113
+ if ch == 27
114
+ @stack.clear
115
+ return ch
116
+ end
117
+ # possible F1..F3 on xterm-color
118
+ if ch == 79 or ch == 91
119
+ #$log.debug " got 27, #{ch}, waiting for one more"
120
+ @stack << ch
121
+ next
122
+ end
123
+ #$log.debug "stack SIZE #{@stack.size}, #{@stack.inspect}, ch: #{ch}"
124
+ if @stack == [27,79]
125
+ # xterm-color
126
+ case ch
127
+ when 80
128
+ ch = KEY_F1
129
+ when 81
130
+ ch = KEY_F2
131
+ when 82
132
+ ch = KEY_F3
133
+ when 83
134
+ ch = KEY_F4
135
+ end
136
+ @stack.clear
137
+ return ch
138
+ elsif @stack == [27, 91]
139
+ if ch == 90
140
+ @stack.clear
141
+ return KEY_BTAB # backtab
142
+ end
143
+ end
144
+ # the usual Meta combos. (alt)
145
+ ch = 128 + ch
146
+ @stack.clear
147
+ return ch
148
+ end
149
+ # append a 27 to stack, actually one can use a flag too
150
+ if ch == 27
151
+ @stack << 27
152
+ next
153
+ end
154
+ return ch
155
+ end
156
+ end
157
+
158
+ def clear
159
+ # return unless visible?
160
+ move 0, 0
161
+ puts *Array.new(height){ ' ' * (width - 1) }
162
+ end
163
+
164
+
165
+ def visible?
166
+ @visible
167
+ end
168
+ ##
169
+ # added by rk 2008-11-29 19:01
170
+ # I usually use this, not the others ones here
171
+ # @param r - row
172
+ # @param c - col
173
+ # @param string - text to print
174
+ # @param color - color pair
175
+ # @ param att - ncurses attribute: normal, bold, reverse, blink,
176
+ # underline
177
+ def printstring(r,c,string, color, att = Ncurses::A_NORMAL)
178
+ prv_printstring(r,c,string, color, att )
179
+ end
180
+
181
+ ## name changed from printstring to prv_prinstring
182
+ def prv_printstring(r,c,string, color, att = Ncurses::A_NORMAL)
183
+
184
+ #$log.debug " #{@name} inside window printstring r #{r} c #{c} #{string} "
185
+ att = Ncurses::A_NORMAL if att.nil?
186
+ case att.to_s.downcase
187
+ when 'normal'
188
+ att = Ncurses::A_NORMAL
189
+ when 'underline'
190
+ att = Ncurses::A_UNDERLINE
191
+ when 'bold'
192
+ att = Ncurses::A_BOLD
193
+ when 'blink'
194
+ att = Ncurses::A_BLINK # unlikely to work
195
+ when 'reverse'
196
+ att = Ncurses::A_REVERSE
197
+ end
198
+
199
+ attron(Ncurses.COLOR_PAIR(color) | att)
200
+ # we should not print beyond window coordinates
201
+ # trying out on 2009-01-03 19:29
202
+ width = Ncurses.COLS
203
+ # the next line won't ensure we don't write outside some bounds like table
204
+ #string = string[0..(width-c)] if c + string.length > width
205
+ #$log.debug "PRINT len:#{string.length}, #{Ncurses.COLS}, #{r}, #{c} w: #{@window} "
206
+ mvprintw(r, c, "%s", string);
207
+ attroff(Ncurses.COLOR_PAIR(color) | att)
208
+ end
209
+ # added by rk 2008-11-29 19:01
210
+ # Since these methods write directly to window they are not advised
211
+ # since clearing previous message we don't know how much to clear.
212
+ # Best to map error_message to a label.
213
+ # 2010-09-13 00:22 WE should not use these any longer.
214
+ # Application should create a label and map a Variable named
215
+ # $errormessage to it. We should only update the Variable
216
+ def print_error_message text=$error_message
217
+ r = $error_message_row || Ncurses.LINES-1
218
+ c = $error_message_col || (Ncurses.COLS-text.length)/2
219
+
220
+ $log.debug "got ERROR MESSAGE #{text} row #{r} "
221
+ clear_error r, $datacolor
222
+ printstring r, c, text, color = $promptcolor
223
+ $error_message_clear_pending = true
224
+ end
225
+ # added by rk 2008-11-29 19:01
226
+ def print_status_message text=$status_message
227
+ r = $status_message_row || Ncurses.LINES-1
228
+ clear_error r, $datacolor
229
+ # print it in centre
230
+ printstring r, (Ncurses.COLS-text.length)/2, text, color = $promptcolor
231
+ end
232
+ # Clear error message printed
233
+ # I am not only clearing if something was printed. This is since
234
+ # certain small forms like TabbedForm top form throw an error on printstring.
235
+ #
236
+ def clear_error r = $error_message_row, color = $datacolor
237
+ return unless $error_message_clear_pending
238
+ c = $error_message_col || (Ncurses.COLS-text.length)/2
239
+ sz = $error_message_size || Ncurses.COLS
240
+ printstring(r, c, "%-*s" % [sz, " "], color)
241
+ $error_message_clear_pending = false
242
+ end
243
+ ##
244
+ def get_window; @window; end
245
+ def to_s; @name || self; end
246
+ end
247
+ end