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