rbcurse-core 0.0.0

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 (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,71 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: colorparser.rb
3
+ # Description: Default parse for our tmux format
4
+ # The aim is to be able to specify parsers so different kinds
5
+ # of formatting or documents can be used, such as ANSI formatted
6
+ # manpages.
7
+ # Author: rkumar http://github.com/rkumar/rbcurse/
8
+ # Date: 07.11.11 - 13:17
9
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+ # Last update: use ,,L
11
+ # ----------------------------------------------------------------------------- #
12
+ # == TODO
13
+ # - perhaps we can compile the regexp once and reuse
14
+ #
15
+
16
+ class DefaultColorParser
17
+
18
+ # NOTE: Experimental and minimal
19
+ # parses the formatted string and yields either an array of color, bgcolor and attrib
20
+ # or the text. This will be called by convert_to_chunk.
21
+ #
22
+ # Currently, assumes colors and attributes are correct. No error checking or fancy stuff.
23
+ # s="#[fg=green]hello there#[fg=yellow, bg=black, dim]"
24
+ # @since 1.4.1 2011-11-3 experimental, can change
25
+ # @return [nil] knows nothign about output format.
26
+
27
+ def parse_format s # yields attribs or text
28
+ ## set default colors
29
+ color = :white
30
+ bgcolor = :black
31
+ attrib = FFI::NCurses::A_NORMAL
32
+ text = ""
33
+
34
+ ## split #[...]
35
+ a = s.split /(#\[[^\]]*\])/
36
+ a.each { |e|
37
+ ## process color or attrib portion
38
+ if e[0,2] == "#[" && e[-1] == "]"
39
+ # now resetting 1:20 PM November 3, 2011 , earlier we were carrying over
40
+ color, bgcolor, attrib = nil, nil, nil
41
+ catch(:done) do
42
+ e = e[2..-2]
43
+ ## first split on commas to separate fg, bg and attr
44
+ atts = e.split /\s*,\s*/
45
+ atts.each { |att|
46
+ ## next split on =
47
+ part = att.split /\s*=\s*/
48
+ case part[0]
49
+ when "fg"
50
+ color = part[1]
51
+ when "bg"
52
+ bgcolor = part[1]
53
+ when "/end", "end"
54
+ yield :endcolor if block_given?
55
+ #next
56
+ throw :done
57
+ else
58
+ # attrib
59
+ attrib = part[0]
60
+ end
61
+ }
62
+ yield [color,bgcolor,attrib] if block_given?
63
+ end # catch
64
+ else
65
+ text = e
66
+ yield text if block_given?
67
+ end
68
+ }
69
+ end
70
+
71
+ end
@@ -0,0 +1,31 @@
1
+ # Allow some objects to take focus when a certain key is pressed.
2
+ # This is for objects like scrollbars and grabbars. We don't want these always
3
+ # getting focus, only sometimes when we want to resize panes.
4
+ # This will not only be included by Form but by containers such as Vimsplit
5
+ # or MasterDetail.
6
+ # Usage: the idea is that when you create grabbars, you would add them to the FocusManager
7
+ # Thus they would remain non-focusable on creation. When hte user presses (say F3) then
8
+ # make_focusable is called, or toggle_focusable. Now user can press TAB and access
9
+ # these bars. When he is done he can toggle again.
10
+ # TODO: we might add a Circular class here so user can traverse only these objects
11
+ module RubyCurses
12
+ module FocusManager
13
+ extend self
14
+ attr_reader :focusables
15
+ # add a component to this list so it can be made focusable later
16
+ def add component
17
+ @focusables ||= []
18
+ @focusables << component
19
+ self
20
+ end
21
+ def make_focusable bool=true
22
+ @focusing = bool
23
+ @focusables.each { |e| e.focusable(bool) }
24
+ end
25
+ def toggle_focusable
26
+ return unless @focusables
27
+ alert "FocusManager Making #{@focusables.length} objects #{!@focusing} "
28
+ make_focusable !@focusing
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,189 @@
1
+ =begin
2
+ * Name: PadReader.rb
3
+ * Description : This is an independent file viewer that uses a Pad and traps keys
4
+ * Author: rkumar (http://github.com/rkumar/rbcurse/)
5
+ * Date: 22.10.11 - 20:35
6
+ * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
7
+ * Last update: 2011-11-14 - 20:57
8
+
9
+ == CHANGES
10
+ == TODO
11
+ make the window configurable so we can move to a textview that is pad based, later even list ?
12
+ Note that cursor does not move, in real life applicatino cursor must move to bottom row
13
+ and only then scrolling should start.
14
+ NOTE: I have continued this in textpad which is a widget that uses pads to scroll.
15
+ This is very rough, i may work on this more later.
16
+ =end
17
+ require 'rbcurse'
18
+
19
+ include RubyCurses
20
+ class PadReader
21
+
22
+ # You may pass height, width, row and col for creating a window otherwise a fullscreen window
23
+ # will be created. If you pass a window from caller then that window will be used.
24
+ # Some keys are trapped, jkhl space, pgup, pgdown, end, home, t b
25
+ # This is currently very minimal and was created to get me started to integrating
26
+ # pads into other classes such as textview.
27
+ def initialize config={}, &block
28
+
29
+ @config = config
30
+ @rows = FFI::NCurses.LINES-1
31
+ @cols = FFI::NCurses.COLS-1
32
+ @prow = @pcol = 0
33
+ @startrow = 0
34
+ @startcol = 0
35
+
36
+ h = config.fetch(:height, 0)
37
+ w = config.fetch(:width, 0)
38
+ t = config.fetch(:row, 0)
39
+ l = config.fetch(:col, 0)
40
+ @rows = h unless h == 0
41
+ @cols = w unless w == 0
42
+ @startrow = t unless t == 0
43
+ @startcol = l unless l == 0
44
+ @suppress_border = config[:suppress_border]
45
+ unless @suppress_border
46
+ @startrow += 1
47
+ @startcol += 1
48
+ @rows -=3 # 3 is since print_border_only reduces one from width, to check whether this is correct
49
+ @cols -=3
50
+ end
51
+ @top = t
52
+ @left = l
53
+ view_file config[:filename]
54
+ @window = config[:window] || VER::Window.new(:height => h, :width => w, :top => t, :left => l)
55
+ # print border reduces on from width for some historical reason
56
+ @window.print_border_only @top, @left, h-1, w, $datacolor
57
+ @ph = @content_rows
58
+ @pw = @content_cols # get max col
59
+ @pad = FFI::NCurses.newpad(@ph, @pw)
60
+
61
+ Ncurses::Panel.update_panels
62
+ @content.each_index { |ix|
63
+
64
+ FFI::NCurses.mvwaddstr(@pad,ix, 0, @content[ix])
65
+ }
66
+ @window.wrefresh
67
+ padrefresh
68
+ #FFI::NCurses.prefresh(@pad, 0,0, @startrow ,@startcol, @rows,@cols);
69
+
70
+ @window.bkgd(Ncurses.COLOR_PAIR(5));
71
+ FFI::NCurses.keypad(@pad, true);
72
+ #@form = Form.new @window
73
+ config[:row] = config[:col] = 0 # ??? XXX
74
+ end
75
+
76
+ private
77
+ def view_file(filename)
78
+ @file = filename
79
+ @content = File.open(filename,"r").readlines
80
+ @content_rows = @content.count
81
+ @content_cols = content_cols()
82
+ #run()
83
+ end
84
+ # write pad onto window
85
+ private
86
+ def padrefresh
87
+ FFI::NCurses.prefresh(@pad,@prow,@pcol, @startrow,@startcol, @rows + @startrow,@cols+@startcol);
88
+ end
89
+ # returns button index
90
+ # Call this after instantiating the window
91
+ public
92
+ def run
93
+ #@form.repaint
94
+ #@window.wrefresh
95
+ return handle_keys
96
+ end
97
+
98
+ # convenience method
99
+ private
100
+ def key x
101
+ x.getbyte(0)
102
+ end
103
+ def content_cols
104
+ longest = @content.max_by(&:length)
105
+ longest.length
106
+ end
107
+
108
+ # returns button index
109
+ private
110
+ def handle_keys
111
+ ht = @window.height.ifzero FFI::NCurses.LINES-1
112
+ buttonindex = catch(:close) do
113
+ @maxrow = @content_rows - @rows
114
+ @maxcol = @content_cols - @cols
115
+ while((ch = @window.getchar()) != FFI::NCurses::KEY_F10 )
116
+ #while((ch = FFI::NCurses.wgetch(@pad)) != FFI::NCurses::KEY_F10 )
117
+ break if ch == ?\C-q.getbyte(0)
118
+ begin
119
+ case ch
120
+ when key(?g), 279 # home as per iterm2
121
+ @prow = 0
122
+ when key(?b), key(?G), 277 # end as per iterm2
123
+ @prow = @maxrow-1
124
+ when key(?j)
125
+ @prow += 1
126
+ when key(?k)
127
+ @prow -= 1
128
+ when 32, 338 # Page Down abd Page Up as per iTerm2
129
+ @prow += 10
130
+ when key(?\C-d)
131
+ @prow += ht
132
+ when key(?\C-b)
133
+ @prow -= ht
134
+ when 339
135
+ @prow -= 10
136
+ when key(?l)
137
+ @pcol += 1
138
+ when key(?$)
139
+ @pcol = @maxcol - 1
140
+ when key(?h)
141
+ @pcol -= 1
142
+ when key(?0)
143
+ @pcol = 0
144
+ when key(?q)
145
+ throw :close
146
+ else
147
+ alert " #{ch} not mapped "
148
+ end
149
+ @prow = 0 if @prow < 0
150
+ @pcol = 0 if @pcol < 0
151
+ if @prow > @maxrow-1
152
+ @prow = @maxrow-1
153
+ end
154
+ if @pcol > @maxcol-1
155
+ @pcol = @maxcol-1
156
+ end
157
+ #@window.wclear
158
+ #FFI::NCurses.prefresh(@pad,@prow,@pcol, @startrow,0, @rows,@cols);
159
+ padrefresh
160
+ Ncurses::Panel.update_panels
161
+ #@form.handle_key(ch)
162
+ #@window.wrefresh
163
+ rescue => err
164
+ $log.debug( err) if err
165
+ $log.debug(err.backtrace.join("\n")) if err
166
+ alert "Got an exception in PadReader: #{err}. Check log"
167
+ $error_message.value = ""
168
+ ensure
169
+ end
170
+
171
+ end # while loop
172
+ end # close
173
+ $log.debug "XXX: CALLER GOT #{buttonindex} "
174
+ @window.destroy unless @config[:window]
175
+ FFI::NCurses.delwin(@pad)
176
+ return buttonindex
177
+ end
178
+ end
179
+ if __FILE__ == $PROGRAM_NAME
180
+ require 'rbcurse/core/util/app'
181
+ App.new do
182
+ #status_line :row => FFI::NCurses.LINES-1
183
+ @form.repaint
184
+ #p = PadReader.new :filename => "padreader.rb", :height => 20, :width => 60, :row => 4, :col => 4, :window => @window, :suppress_border => true
185
+ p = PadReader.new :filename => "padreader.rb", :height => FFI::NCurses.LINES-1, :width => 0, :row => 0, :col => 0, :window => @window, :suppress_border => true
186
+ p.run
187
+ throw :close
188
+ end
189
+ end
@@ -0,0 +1,587 @@
1
+ =begin
2
+ * Name: rcommandwindow: pops up a status message at bottom of screen
3
+ creating a new window, so we don't have to worry about having window
4
+ handle.
5
+ Can use with say, ask etc. wsay wask wagree etc !
6
+ * Description
7
+ * Author: rkumar (arunachalesha)
8
+ * Date: 2008-11-19 12:49
9
+ * License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
10
+ * file separated on 2009-01-13 22:39
11
+
12
+ =end
13
+ require 'rbcurse'
14
+
15
+ module RubyCurses
16
+ ##
17
+ #
18
+ #
19
+ class CommandWindow
20
+ include RubyCurses::Utils
21
+ dsl_accessor :box
22
+ dsl_accessor :title
23
+ attr_reader :config
24
+ attr_reader :layout
25
+ attr_reader :window # required for keyboard or printing
26
+ dsl_accessor :height, :width, :top, :left # 2009-01-06 00:05 after removing meth missing
27
+
28
+ def initialize form=nil, aconfig={}, &block
29
+ @config = aconfig
30
+ @config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
31
+ instance_eval &block if block_given?
32
+ if @layout.nil?
33
+ set_layout(1,80, -1, 0)
34
+ end
35
+ @height = @layout[:height]
36
+ @width = @layout[:width]
37
+ @window = VER::Window.new(@layout)
38
+ @start = 0 # row for display of text with paging
39
+ @list = []
40
+ require 'forwardable'
41
+ require 'rbcurse/core/util/bottomline'
42
+ @bottomline = Bottomline.new @window, 0
43
+ @bottomline.name = "rcommandwindow's bl"
44
+ extend Forwardable
45
+ def_delegators :@bottomline, :ask, :say, :agree, :choose #, :display_text_interactive
46
+ if @box == :border
47
+ @window.box 0,0
48
+ elsif @box
49
+ @window.attron(Ncurses.COLOR_PAIR($normalcolor) | Ncurses::A_REVERSE)
50
+ @window.mvhline 0,0,1,@width
51
+ @window.printstring 0,0,@title, $normalcolor #, 'normal' if @title
52
+ @window.attroff(Ncurses.COLOR_PAIR($normalcolor) | Ncurses::A_REVERSE)
53
+ else
54
+ #@window.printstring 0,0,@title, $normalcolor, 'reverse' if @title
55
+ title @title
56
+ end
57
+ @window.wrefresh
58
+ @panel = @window.panel
59
+ Ncurses::Panel.update_panels
60
+ @window.wrefresh
61
+ @row_offset = 0
62
+ if @box
63
+ @row_offset = 1
64
+ end
65
+ end
66
+ # modify the window title, or get it if no params passed.
67
+ def title t=nil
68
+ return @title unless t
69
+ @title = t
70
+ @window.printstring 0,0,@title, $normalcolor, 'reverse' if @title
71
+ end
72
+ ##
73
+ ## message box
74
+ def stopping?
75
+ @stop
76
+ end
77
+ # todo handle mappings, so user can map keys TODO
78
+ def handle_keys
79
+ begin
80
+ while((ch = @window.getchar()) != 999 )
81
+ case ch
82
+ when -1
83
+ next
84
+ else
85
+ press ch
86
+ break if @stop
87
+ yield ch if block_given?
88
+ end
89
+ end
90
+ ensure
91
+ destroy
92
+ end
93
+ return #@selected_index
94
+ end
95
+ # handles a key, commandline
96
+ def press ch
97
+ ch = ch.getbyte(0) if ch.class==String ## 1.9
98
+ $log.debug " XXX press #{ch} " if $log.debug?
99
+ case ch
100
+ when -1
101
+ return
102
+ when KEY_F1, 27, ?\C-q.getbyte(0)
103
+ @stop = true
104
+ return
105
+ when KEY_ENTER, 10, 13
106
+ #$log.debug "popup ENTER : #{@selected_index} "
107
+ #$log.debug "popup ENTER : #{field.name}" if !field.nil?
108
+ @stop = true
109
+ return
110
+ when ?\C-d.getbyte(0)
111
+ @start += @height-1
112
+ bounds_check
113
+ when KEY_UP
114
+ @start -= 1
115
+ @start = 0 if @start < 0
116
+ when KEY_DOWN
117
+ @start += 1
118
+ bounds_check
119
+ when ?\C-b.getbyte(0)
120
+ @start -= @height-1
121
+ @start = 0 if @start < 0
122
+ when 0
123
+ @start = 0
124
+ end
125
+ Ncurses::Panel.update_panels();
126
+ Ncurses.doupdate();
127
+ @window.wrefresh
128
+ end
129
+ # might as well add more keys for paging.
130
+ def configure(*val , &block)
131
+ case val.size
132
+ when 1
133
+ return @config[val[0]]
134
+ when 2
135
+ @config[val[0]] = val[1]
136
+ instance_variable_set("@#{val[0]}", val[1])
137
+ end
138
+ instance_eval &block if block_given?
139
+ end
140
+ def cget param
141
+ @config[param]
142
+ end
143
+
144
+ def set_layout(height=0, width=0, top=0, left=0)
145
+ # negative means top should be n rows from last line. -1 is last line
146
+ if top < 0
147
+ top = Ncurses.LINES-top
148
+ end
149
+ @layout = { :height => height, :width => width, :top => top, :left => left }
150
+ @height = height
151
+ @width = width
152
+ end
153
+ def destroy
154
+ $log.debug "DESTROY : rcommandwindow"
155
+ if @window
156
+ begin
157
+ panel = @window.panel
158
+ Ncurses::Panel.del_panel(panel.pointer) if panel
159
+ @window.delwin
160
+ rescue => exc
161
+ end
162
+ end
163
+ end
164
+ #
165
+ # Displays list in a window at bottom of screen, if large then 2 or 3 columns.
166
+ # @param [Array] list of string to be displayed
167
+ # @param [Hash] configuration options: indexing and indexcolor
168
+ # indexing - can be letter or number. Anything else will be ignored, however
169
+ # it will result in first letter being highlighted in indexcolor
170
+ # indexcolor - color of mnemonic, default green
171
+ def display_menu list, options={}
172
+ indexing = options[:indexing]
173
+ indexcolor = options[:indexcolor] || get_color($normalcolor, :yellow, :black)
174
+ indexatt = Ncurses::A_BOLD
175
+ #
176
+ # the index to start from (used when scrolling a long menu such as file list)
177
+ startindex = options[:startindex] || 0
178
+
179
+ max_cols = 3 # maximum no of columns, we will reduce based on data size
180
+ l_succ = "`"
181
+ act_height = @height
182
+ if @box
183
+ act_height = @height - 2
184
+ end
185
+ lh = list.size
186
+ if lh < act_height
187
+ $log.debug "DDD inside one window" if $log.debug?
188
+ list.each_with_index { |e, i|
189
+ text = e
190
+ case e
191
+ when Array
192
+ text = e.first + " ..."
193
+ end
194
+ if indexing == :number
195
+ mnem = i+1
196
+ text = "%d. %s" % [i+1, text]
197
+ elsif indexing == :letter
198
+ mnem = l_succ.succ!
199
+ text = "%s. %s" % [mnem, text]
200
+ end
201
+ @window.printstring i+@row_offset, 1, text, $normalcolor
202
+ if indexing
203
+ window.mvchgat(y=i+@row_offset, x=1, max=1, indexatt, indexcolor, nil)
204
+ end
205
+ }
206
+ else
207
+ $log.debug "DDD inside two window" if $log.debug?
208
+ row = 0
209
+ h = act_height
210
+ cols = (lh*1.0 / h).ceil
211
+ cols = max_cols if cols > max_cols
212
+ # sometimes elements are large like directory paths, so check size
213
+ datasize = list.first.length
214
+ if datasize > @width/3 # keep safety margin since checking only first row
215
+ cols = 1
216
+ elsif datasize > @width/2
217
+ cols = [2,cols].min
218
+ end
219
+ adv = (@width/cols).to_i
220
+ colct = 0
221
+ col = 1
222
+ $log.debug "DDDcols #{cols}, adv #{adv} size: #{lh} h: #{act_height} w #{@width} " if $log.debug?
223
+ list.each_with_index { |e, i|
224
+ text = e
225
+ # signify that there's a deeper level
226
+ case e
227
+ when Array
228
+ text = e.first + "..."
229
+ end
230
+ if indexing == :number
231
+ mnem = i+1
232
+ text = "%d. %s" % [mnem, text]
233
+ elsif indexing == :letter
234
+ mnem = l_succ.succ!
235
+ text = "%s. %s" % [mnem, text]
236
+ end
237
+ # print only within range and window height
238
+ if i >= startindex && row < @window.actual_height
239
+ $log.debug "XXX: MENU #{i} > #{startindex} row #{row} col #{col} "
240
+ @window.printstring row+@row_offset, col, text, $normalcolor
241
+ if indexing
242
+ @window.mvchgat(y=row+@row_offset, x=col, max=1, indexatt, indexcolor, nil)
243
+ end
244
+ colct += 1
245
+ if colct == cols
246
+ col = 1
247
+ row += 1
248
+ colct = 0
249
+ else
250
+ col += adv
251
+ end
252
+ end # startindex
253
+ }
254
+ end
255
+ Ncurses::Panel.update_panels();
256
+ Ncurses.doupdate();
257
+ @window.wrefresh
258
+ end
259
+ # refresh whatevers painted onto the window
260
+ def refresh
261
+ Ncurses::Panel.update_panels();
262
+ Ncurses.doupdate();
263
+ @window.wrefresh
264
+ end
265
+ # clears the window, leaving the title line as is, from row 1 onwards
266
+ def clear
267
+ @window.wmove 1,1
268
+ @window.wclrtobot
269
+ @window.box 0,0 if @box == :border
270
+ # lower line of border will get erased currently since we are writing to
271
+ # last line FIXME
272
+ end
273
+ def display_interactive text, config={}
274
+ if @to
275
+ @to.content text
276
+ else
277
+ config[:box] = @box
278
+ @to = ListObject.new self, text, config
279
+ end
280
+ yield @to if block_given?
281
+ @to.display_interactive # this returns the item selected
282
+ @to # this will return the ListObject to the user with list and current_index
283
+ end
284
+ # non interactive list display - EACH CALL IS CREATING A LIST OBJECT
285
+ def udisplay_list text, config={}
286
+ if @to
287
+ @to.content text
288
+ else
289
+ config[:box] = @box
290
+ @to = ListObject.new self, text, config
291
+ end
292
+ #@to ||= ListObject.new self, text, config
293
+ yield @to if block_given?
294
+ @to.display_content
295
+ @to
296
+ end
297
+ # displays a list
298
+ class ListObject
299
+ attr_reader :cw
300
+ attr_reader :list
301
+ attr_reader :current_index
302
+ attr_accessor :focussed_attrib
303
+ attr_accessor :focussed_symbol
304
+ def initialize cw, _list, config={}
305
+ @cw = cw
306
+ layout = @cw.layout
307
+ @window = @cw.window
308
+ @height = layout[:height]
309
+ @width = layout[:width]
310
+ content(_list)
311
+ @height_adjust = config.fetch(:box, true) == :border ? 3 : 2
312
+ @selected_index = nil
313
+ @current_index = 0
314
+ @row_offset = 1
315
+ @toprow = 0
316
+ $multiplier = 0 # till we can do something
317
+
318
+ @focussed_symbol = ''
319
+ @row_selected_symbol = ''
320
+ #@show_selector = true
321
+ if @show_selector
322
+ @row_selected_symbol ||= '*'
323
+ @row_unselected_symbol ||= ' '
324
+ @left_margin ||= @row_selected_symbol.length
325
+ end
326
+ #@show_selector = true
327
+ #@row_selected_symbol = '*'
328
+ #@row_unselected_symbol = ' '
329
+ end
330
+ def content txt, config={}
331
+ @current_index = 0 # sometimes it gets left at a higher value than there are rows to show
332
+ case txt
333
+ when String
334
+ txt = wrap_text(txt, @width-2).split("\n")
335
+ when Array
336
+ # okay
337
+ end
338
+ @list = txt
339
+ end
340
+ # maybe we should just use a textview or label rather than try to
341
+ # do it all voer again !
342
+ def display_interactive
343
+ display_content
344
+ while !@stop
345
+ @window.wrefresh # FFI 2011-09-12
346
+ # FIXME only clear and redisplay if change has happened (repaint_require)
347
+ handle_keys { |ch| @cw.clear; display_content }
348
+ end
349
+ return @list[@current_index]
350
+ end
351
+ def is_row_selected row
352
+ @selected_index == row
353
+ end
354
+
355
+ def scrollatrow
356
+ @height - 3
357
+ end
358
+ def row_count
359
+ @list.size
360
+ end
361
+ def rowcol
362
+ return @row_offset, @col_offset
363
+ end
364
+ def display_content #:nodoc:
365
+
366
+ @graphic = @window
367
+ @start ||= 0
368
+ @toprow ||= 0
369
+ @left_margin ||= @row_selected_symbol.length + @focussed_symbol.length
370
+
371
+ #print_borders unless @suppress_borders # do this once only, unless everything changes
372
+ #maxlen = @maxlen ||= @width-2
373
+ tm = @list
374
+ rc = tm.size
375
+ @col_offset = 1
376
+ #@longest_line = @width
377
+ if rc > 0 # just added in case no data passed
378
+ #tr = @start #@toprow
379
+ tr = @toprow
380
+ acolor = get_color $datacolor
381
+ #h = @height - 3 #2
382
+ h = @height - @height_adjust
383
+ r,c = @row_offset, @col_offset
384
+ 0.upto(h) do |hh|
385
+ crow = tr+hh
386
+ if crow < rc
387
+ focussed = @current_index == crow # row focussed ?
388
+ selected = is_row_selected crow
389
+ content = tm[crow] # 2009-01-17 18:37 chomp giving error in some cases says frozen
390
+ # by now it has to be a String
391
+ ## set the selector symbol if requested
392
+ selection_symbol = ''
393
+ if @show_selector
394
+ if selected
395
+ selection_symbol = @row_selected_symbol
396
+ else
397
+ selection_symbol = @row_unselected_symbol
398
+ end
399
+ @graphic.printstring r+hh, c, selection_symbol, acolor,@attr
400
+ end
401
+ #renderer = get_default_cell_renderer_for_class content.class.to_s
402
+ if focussed
403
+ if @focussed_symbol
404
+ @graphic.printstring r+hh, c, @focussed_symbol, acolor,@attr
405
+ end
406
+ @graphic.printstring r+hh, c+@left_margin, content, acolor, @focussed_attrib || 'reverse'
407
+ else
408
+ @graphic.printstring r+hh, c+@left_margin, content, acolor,@attr
409
+ end
410
+ #renderer.repaint @graphic, r+hh, c+@left_margin, crow, content, focussed, selected
411
+ else
412
+ # clear rows
413
+ @graphic.printstring r+hh, c, " " * (@width-2), acolor,@attr
414
+ end
415
+ end
416
+ end # rc == 0
417
+ set_form_row
418
+ end
419
+ # listobject
420
+ def press ch # list TODO copy from rbasiclist
421
+ ch = ch.getbyte(0) if ch.class==String ## 1.9
422
+ $log.debug " XXX press #{ch} " if $log.debug?
423
+ case ch
424
+ when -1
425
+ return
426
+ when KEY_F1, 27, ?\C-q.getbyte(0)
427
+ @stop = true
428
+ return
429
+ when KEY_ENTER, 10, 13
430
+ #$log.debug "popup ENTER : #{@selected_index} "
431
+ #$log.debug "popup ENTER : #{field.name}" if !field.nil?
432
+ @stop = true
433
+ return
434
+ when 32, ?\C-d.getbyte(0)
435
+ scroll_forward
436
+ #@start += @height-1
437
+ #bounds_check
438
+ when KEY_UP, ?k.getbyte(0)
439
+ previous_row
440
+ #@start -= 1
441
+ #@current_index -= 1
442
+ #@current_index = 0 if @current_index < 0
443
+ #@start = 0 if @start < 0
444
+ when KEY_DOWN, ?j.getbyte(0)
445
+ next_row
446
+ #@start += 1
447
+ #@current_index += 1
448
+ #bounds_check
449
+ when ?\C-b.getbyte(0)
450
+ scroll_backward
451
+ #@start -= @height-1
452
+ #@start = 0 if @start < 0
453
+ when 0, ?g.getbyte(0)
454
+ goto_top
455
+ when ?G.getbyte(0)
456
+ goto_bottom
457
+ end
458
+ #@form.repaint
459
+ Ncurses::Panel.update_panels();
460
+ Ncurses.doupdate();
461
+ @window.wrefresh
462
+ end
463
+
464
+ def previous_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
465
+ #return :UNHANDLED if @current_index == 0 # EVIL
466
+ return false if @current_index == 0
467
+ @oldrow = @current_index
468
+ num.times {
469
+ @current_index -= 1 if @current_index > 0
470
+ }
471
+ bounds_check
472
+ $multiplier = 0
473
+ end
474
+ alias :up :previous_row
475
+ def next_row num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
476
+ rc = row_count
477
+ return false if @current_index == rc-1
478
+ @oldrow = @current_index
479
+ @current_index += 1*num if @current_index < rc
480
+ bounds_check
481
+ $multiplier = 0
482
+ end
483
+ alias :down :next_row
484
+ def goto_bottom
485
+ @oldrow = @current_index
486
+ rc = row_count
487
+ @current_index = rc -1
488
+ bounds_check
489
+ end
490
+ alias :goto_end :goto_bottom
491
+ def goto_top
492
+ @oldrow = @current_index
493
+ @current_index = 0
494
+ bounds_check
495
+ end
496
+ alias :goto_start :goto_top
497
+ def scroll_backward
498
+ @oldrow = @current_index
499
+ h = scrollatrow()
500
+ m = $multiplier == 0? 1 : $multiplier
501
+ @current_index -= h * m
502
+ bounds_check
503
+ $multiplier = 0
504
+ end
505
+ def scroll_forward
506
+ @oldrow = @current_index
507
+ h = scrollatrow()
508
+ rc = row_count
509
+ m = $multiplier == 0? 1 : $multiplier
510
+ # more rows than box
511
+ if h * m < rc
512
+ @toprow += h+1 #if @current_index+h < rc
513
+ @current_index = @toprow
514
+ else
515
+ # fewer rows than box
516
+ @current_index = rc -1
517
+ end
518
+ #@current_index += h+1 #if @current_index+h < rc
519
+ bounds_check
520
+ end
521
+
522
+ ##
523
+ # please set oldrow before calling this. Store current_index as oldrow before changing. NOTE
524
+ def bounds_check
525
+ h = scrollatrow()
526
+ rc = row_count
527
+
528
+ @current_index = 0 if @current_index < 0 # not lt 0
529
+ @current_index = rc-1 if @current_index >= rc && rc>0 # not gt rowcount
530
+ @toprow = rc-h-1 if rc > h && @toprow > rc - h - 1 # toprow shows full page if possible
531
+ # curr has gone below table, move toprow forward
532
+ if @current_index - @toprow > h
533
+ @toprow = @current_index - h
534
+ elsif @current_index < @toprow
535
+ # curr has gone above table, move toprow up
536
+ @toprow = @current_index
537
+ end
538
+ set_form_row
539
+
540
+ end
541
+
542
+ def set_form_row
543
+ r,c = rowcol
544
+
545
+
546
+ # when the toprow is set externally then cursor can be mispositioned since
547
+ # bounds_check has not been called
548
+ if @current_index < @toprow
549
+ # cursor is outside table
550
+ @current_index = @toprow # ??? only if toprow 2010-10-19 12:56
551
+ end
552
+
553
+ row = r + (@current_index-@toprow)
554
+ # row should not be < r or greater than r+height TODO FIXME
555
+
556
+ #setrowcol row, nil
557
+ @window.wmove row, c
558
+ @window.wrefresh # FFI added to keep cursor display in synch with selection
559
+ end
560
+ def OLDbounds_check #:nodoc:
561
+ @start = 0 if @start < 0
562
+ row_offset = 1
563
+ last = (@list.length)-(@height-row_offset-1)
564
+ if @start > last
565
+ @start = last
566
+ end
567
+ end # bounds_check
568
+ def handle_keys #:nodoc:
569
+ begin
570
+ while((ch = @window.getchar()) != 999 )
571
+ case ch
572
+ when -1
573
+ next
574
+ else
575
+ press ch
576
+ break if @stop
577
+ yield ch if block_given?
578
+ end
579
+ end
580
+ ensure
581
+ @cw.destroy
582
+ end
583
+ return @current_index
584
+ end
585
+ end # class ListObject
586
+ end # class CommandWindow
587
+ end # module