canis 0.0.4

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 (134) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +45 -0
  3. data/CHANGES +52 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +24 -0
  7. data/Rakefile +2 -0
  8. data/canis.gemspec +25 -0
  9. data/examples/alpmenu.rb +46 -0
  10. data/examples/app.sample +19 -0
  11. data/examples/appemail.rb +191 -0
  12. data/examples/atree.rb +105 -0
  13. data/examples/bline.rb +181 -0
  14. data/examples/common/devel.rb +319 -0
  15. data/examples/common/file.rb +93 -0
  16. data/examples/data/README.markdown +9 -0
  17. data/examples/data/brew.txt +38 -0
  18. data/examples/data/color.2 +37 -0
  19. data/examples/data/gemlist.txt +59 -0
  20. data/examples/data/lotr.txt +12 -0
  21. data/examples/data/ports.txt +136 -0
  22. data/examples/data/table.txt +37 -0
  23. data/examples/data/tasks.csv +88 -0
  24. data/examples/data/tasks.txt +27 -0
  25. data/examples/data/todo.txt +16 -0
  26. data/examples/data/todocsv.csv +28 -0
  27. data/examples/data/unix1.txt +21 -0
  28. data/examples/data/unix2.txt +11 -0
  29. data/examples/dbdemo.rb +506 -0
  30. data/examples/dirtree.rb +177 -0
  31. data/examples/newtabbedwindow.rb +100 -0
  32. data/examples/newtesttabp.rb +92 -0
  33. data/examples/tabular.rb +212 -0
  34. data/examples/tasks.rb +179 -0
  35. data/examples/term2.rb +88 -0
  36. data/examples/testbuttons.rb +307 -0
  37. data/examples/testcombo.rb +102 -0
  38. data/examples/testdb.rb +182 -0
  39. data/examples/testfields.rb +208 -0
  40. data/examples/testflowlayout.rb +43 -0
  41. data/examples/testkeypress.rb +98 -0
  42. data/examples/testlistbox.rb +187 -0
  43. data/examples/testlistbox1.rb +199 -0
  44. data/examples/testmessagebox.rb +144 -0
  45. data/examples/testprogress.rb +116 -0
  46. data/examples/testree.rb +107 -0
  47. data/examples/testsplitlayout.rb +53 -0
  48. data/examples/testsplitlayout1.rb +49 -0
  49. data/examples/teststacklayout.rb +48 -0
  50. data/examples/testwsshortcuts.rb +68 -0
  51. data/examples/testwsshortcuts2.rb +129 -0
  52. data/lib/canis.rb +16 -0
  53. data/lib/canis/core/docs/index.txt +104 -0
  54. data/lib/canis/core/docs/list.txt +16 -0
  55. data/lib/canis/core/docs/style_help.yml +34 -0
  56. data/lib/canis/core/docs/tabbedpane.txt +15 -0
  57. data/lib/canis/core/docs/table.txt +31 -0
  58. data/lib/canis/core/docs/textpad.txt +48 -0
  59. data/lib/canis/core/docs/tree.txt +23 -0
  60. data/lib/canis/core/include/.DS_Store +0 -0
  61. data/lib/canis/core/include/action.rb +83 -0
  62. data/lib/canis/core/include/actionmanager.rb +49 -0
  63. data/lib/canis/core/include/appmethods.rb +179 -0
  64. data/lib/canis/core/include/bordertitle.rb +49 -0
  65. data/lib/canis/core/include/canisparser.rb +100 -0
  66. data/lib/canis/core/include/colorparser.rb +437 -0
  67. data/lib/canis/core/include/defaultfilerenderer.rb +64 -0
  68. data/lib/canis/core/include/io.rb +320 -0
  69. data/lib/canis/core/include/layouts/SplitLayout.rb +161 -0
  70. data/lib/canis/core/include/layouts/abstractlayout.rb +213 -0
  71. data/lib/canis/core/include/layouts/flowlayout.rb +104 -0
  72. data/lib/canis/core/include/layouts/stacklayout.rb +109 -0
  73. data/lib/canis/core/include/listbindings.rb +89 -0
  74. data/lib/canis/core/include/listeditable.rb +319 -0
  75. data/lib/canis/core/include/listoperations.rb +61 -0
  76. data/lib/canis/core/include/listselectionmodel.rb +388 -0
  77. data/lib/canis/core/include/multibuffer.rb +173 -0
  78. data/lib/canis/core/include/ractionevent.rb +73 -0
  79. data/lib/canis/core/include/rchangeevent.rb +27 -0
  80. data/lib/canis/core/include/rhistory.rb +95 -0
  81. data/lib/canis/core/include/rinputdataevent.rb +47 -0
  82. data/lib/canis/core/include/textdocument.rb +111 -0
  83. data/lib/canis/core/include/vieditable.rb +175 -0
  84. data/lib/canis/core/include/widgetmenu.rb +66 -0
  85. data/lib/canis/core/system/colormap.rb +165 -0
  86. data/lib/canis/core/system/keydefs.rb +32 -0
  87. data/lib/canis/core/system/ncurses.rb +237 -0
  88. data/lib/canis/core/system/panel.rb +129 -0
  89. data/lib/canis/core/system/window.rb +1081 -0
  90. data/lib/canis/core/util/ansiparser.rb +119 -0
  91. data/lib/canis/core/util/app.rb +696 -0
  92. data/lib/canis/core/util/basestack.rb +412 -0
  93. data/lib/canis/core/util/defaultcolorparser.rb +84 -0
  94. data/lib/canis/core/util/extras/README +5 -0
  95. data/lib/canis/core/util/extras/bottomline.rb +1815 -0
  96. data/lib/canis/core/util/extras/padreader.rb +192 -0
  97. data/lib/canis/core/util/focusmanager.rb +31 -0
  98. data/lib/canis/core/util/helpmanager.rb +160 -0
  99. data/lib/canis/core/util/oldwidgetshortcuts.rb +304 -0
  100. data/lib/canis/core/util/promptmenu.rb +235 -0
  101. data/lib/canis/core/util/rcommandwindow.rb +933 -0
  102. data/lib/canis/core/util/rdialogs.rb +520 -0
  103. data/lib/canis/core/util/textutils.rb +74 -0
  104. data/lib/canis/core/util/viewer.rb +238 -0
  105. data/lib/canis/core/util/widgetshortcuts.rb +508 -0
  106. data/lib/canis/core/widgets/applicationheader.rb +103 -0
  107. data/lib/canis/core/widgets/box.rb +58 -0
  108. data/lib/canis/core/widgets/divider.rb +310 -0
  109. data/lib/canis/core/widgets/extras/README.md +12 -0
  110. data/lib/canis/core/widgets/extras/rtextarea.rb +960 -0
  111. data/lib/canis/core/widgets/extras/stackflow.rb +474 -0
  112. data/lib/canis/core/widgets/keylabelprinter.rb +194 -0
  113. data/lib/canis/core/widgets/listbox.rb +326 -0
  114. data/lib/canis/core/widgets/listfooter.rb +86 -0
  115. data/lib/canis/core/widgets/rcombo.rb +210 -0
  116. data/lib/canis/core/widgets/rcontainer.rb +415 -0
  117. data/lib/canis/core/widgets/rlink.rb +30 -0
  118. data/lib/canis/core/widgets/rmenu.rb +970 -0
  119. data/lib/canis/core/widgets/rmenulink.rb +30 -0
  120. data/lib/canis/core/widgets/rmessagebox.rb +400 -0
  121. data/lib/canis/core/widgets/rprogress.rb +118 -0
  122. data/lib/canis/core/widgets/rtabbedpane.rb +631 -0
  123. data/lib/canis/core/widgets/rtabbedwindow.rb +70 -0
  124. data/lib/canis/core/widgets/rwidget.rb +3634 -0
  125. data/lib/canis/core/widgets/scrollbar.rb +147 -0
  126. data/lib/canis/core/widgets/statusline.rb +113 -0
  127. data/lib/canis/core/widgets/table.rb +1072 -0
  128. data/lib/canis/core/widgets/tabular.rb +264 -0
  129. data/lib/canis/core/widgets/textpad.rb +1674 -0
  130. data/lib/canis/core/widgets/tree.rb +690 -0
  131. data/lib/canis/core/widgets/tree/treecellrenderer.rb +150 -0
  132. data/lib/canis/core/widgets/tree/treemodel.rb +432 -0
  133. data/lib/canis/version.rb +3 -0
  134. metadata +229 -0
@@ -0,0 +1,194 @@
1
+ require 'canis/core/widgets/rwidget'
2
+ #include Ncurses # FFI 2011-09-8
3
+ include Canis
4
+ module Canis
5
+ #
6
+ # This paints labels for various keys at the bottom of the screen, in 2 rows.
7
+ # This is based on alpines last 2 rows. Modes are supported so that the
8
+ # labels change as you enter a widget.
9
+ # For an example, see dbdemo.rb or rfe.rb
10
+ # NOTE: applications using 'App' use a shortcut "dock" to create this.
11
+ #
12
+ # The most minimal keylabel to print one label in first row, and none in second is:
13
+ # [["F1", "Help"], nil]
14
+ # To print 2 labels, one over the other:
15
+ # [["F1", "Help"], ["F10", "Quit"]]
16
+ #
17
+ class KeyLabelPrinter < Widget
18
+ attr_reader :key_labels
19
+ # the current mode (labels are based on mode, changing the mode, changes the labels
20
+ # displayed)
21
+ dsl_property :mode
22
+ # set the color of the labels, overriding the defaults
23
+ dsl_accessor :footer_color_pair
24
+ # set the color of the mnemonic, overriding the defaults
25
+ dsl_accessor :footer_mnemonic_color_pair
26
+ #attr_accessor :row_relative # lets only advertise this when we've tested it out
27
+
28
+ def initialize form, key_labels, config={}, &block
29
+
30
+ @name = "dock"
31
+ case key_labels
32
+ when Hash
33
+ raise "KeyLabelPrinter: KeyLabels cannot be a hash, Array of key labels required. Perhaps you did not pass labels"
34
+ when Array
35
+ else
36
+ raise "KeyLabelPrinter: Array of key labels required. Perhaps you did not pass labels"
37
+ end
38
+ super form, config, &block
39
+ @mode ||= :normal
40
+ #@key_labels = key_labels
41
+ @key_hash = {}
42
+ @key_hash[@mode] = key_labels
43
+ @editable = false
44
+ @focusable = false
45
+ unless @row
46
+ @row_relative = -2
47
+ @row = Ncurses.LINES + @row_relative
48
+ end
49
+ @col ||= 0
50
+ # if negativ row passed we store as relative to bottom, so we can maintain that.
51
+ if @row < 0
52
+ @row_relative = @row
53
+ @row = Ncurses.LINES - @row
54
+ else
55
+ @row_relative = (Ncurses.LINES - @row) * -1
56
+ end
57
+ @cols ||= Ncurses.COLS-1
58
+ @repaint_required = true
59
+ @footer_color_pair ||= $bottomcolor
60
+ @footer_mnemonic_color_pair ||= $reversecolor #2
61
+ end
62
+ def key_labels mode=@mode
63
+ @key_hash[mode]
64
+ end
65
+ # returns the keys as printed. these may or may not help
66
+ # in validation depedign on what you passed as zeroth index
67
+ def get_current_keys
68
+ a = []
69
+ @key_hash[@mode].each do |arr|
70
+ a << arr[0] unless arr.nil?
71
+ end
72
+ return a
73
+ end
74
+ def getvalue
75
+ @key_hash
76
+ end
77
+ def set_key_labels _key_labels, mode=:normal
78
+ @key_hash[mode] = _key_labels
79
+ end
80
+
81
+ ##
82
+ # XXX need to move wrapping etc up and done once.
83
+ def repaint
84
+ return unless @repaint_required
85
+ r,c = rowcol
86
+ # this should only happen if there's a change in window
87
+ if @row_relative
88
+ @row = Ncurses.LINES+@row_relative
89
+ end
90
+ arr = key_labels()
91
+ print_key_labels(arr, mode=@mode)
92
+ @repaint_required = false
93
+ end
94
+ # ?? does not use mode, i think key_labels is unused. a hash is now used 2011-10-11 XXX FIXME
95
+ # WARNING, i have not tested this after changing it.
96
+ def append_key_label key, label, mode=@mode
97
+ #@key_labels << [key, label] if !@key_labels.include? [key, label]
98
+ @key_hash[mode] << [key, label] if !@key_hash[mode].include? [key, label]
99
+ @repaint_required = true
100
+ end
101
+ def print_key_labels(arr = key_labels(), mode=@mode)
102
+ #return if !@show_key_labels # XXX
103
+ @win ||= @form.window
104
+ #$log.debug "XXX: PKL #{arr.length}, #{arr}"
105
+ @padding = @cols / (arr.length/2)
106
+ posx = 0
107
+ even = []
108
+ odd = []
109
+ arr.each_index { |i|
110
+ if i % 2 == 0
111
+ #arr[i+1] = ['',''] if arr[i+1].nil?
112
+ nextarr = arr[i+1] || ['', '']
113
+ keyw = [arr[i][0].length, nextarr[0].length].max
114
+ labelw = [arr[i][1].length, nextarr[1].length].max
115
+
116
+ even << [ sprintf("%*s", keyw, arr[i][0]), sprintf("%-*s", labelw, arr[i][1]) ]
117
+ odd << [ sprintf("%*s", keyw, nextarr[0]), sprintf("%-*s", labelw, nextarr[1]) ]
118
+ #$log.debug("loop even: #{even.inspect}")
119
+ else
120
+ end
121
+ }
122
+ #$log.debug("even: #{even.inspect}")
123
+ #$log.debug("odd : #{odd.inspect}")
124
+ #posy = @barrow-1
125
+ posy = @row
126
+ print_key_labels_row(posy, posx, even)
127
+ posy = @row+1
128
+ print_key_labels_row(posy, posx, odd)
129
+ # uncommented next line after ffi-ncurses else not showing till key press FFI 2011-09-17
130
+ @win.wrefresh # needed else secod row not shown after askchoice XXX
131
+ end
132
+ def print_key_labels_row(posy, posx, arr)
133
+ # FIXME: this logic of padding needs to take into account
134
+ # width of window
135
+ padding = 8
136
+ padding = 4 if arr.length > 5
137
+ padding = 2 if arr.length > 7
138
+ padding = 0 if arr.length > 9
139
+ #padding = @padding # XXX 2008-11-13 23:01
140
+ my_form_win = @win
141
+ @win.printstring(posy,0, "%-*s" % [@cols," "], @footer_color_pair, @attr)
142
+ arr.each do |kl|
143
+ key = kl[0]
144
+ lab = kl[1]
145
+ if key !="" # don't print that white blank space for fillers
146
+ color_pair= @footer_mnemonic_color_pair # $reversecolor #2
147
+ x = posx + (key.length - key.strip.length)
148
+ my_form_win.attron(Ncurses.COLOR_PAIR(color_pair))
149
+ my_form_win.mvprintw(posy, x, "%s" % kl[0].strip );
150
+ my_form_win.attroff(Ncurses.COLOR_PAIR(color_pair))
151
+ end
152
+ color_pair=@footer_color_pair
153
+ posx = posx + kl[0].length
154
+ my_form_win.attron(Ncurses.COLOR_PAIR(color_pair))
155
+
156
+ #lab = sprintf(" %s %*s" , kl[1], padding, " ");
157
+ lab = sprintf(" %s %s" , kl[1], " "*padding);
158
+ my_form_win.mvprintw(posy, posx, lab)
159
+ my_form_win.attroff(Ncurses.COLOR_PAIR(color_pair))
160
+ posx = posx + lab.length
161
+ end
162
+ end
163
+ ##
164
+ # updates existing label with a new one.
165
+ # @return true if updated, else false
166
+ # @example update "C-x", "C-x", "Disable"
167
+ def update_application_key_label(display_code, new_display_code, text)
168
+ @repaint_required = true
169
+ labels = key_labels()
170
+ raise "labels are nil !!!" unless labels
171
+ labels.each_index do |ix|
172
+ lab = labels[ix]
173
+ next if lab.nil?
174
+ if lab[0] == display_code
175
+ labels[ix] = [new_display_code , text]
176
+ $log.debug("updated #{labels[ix]}")
177
+ return true
178
+ end
179
+ end
180
+ return false
181
+ end
182
+ alias :update :update_application_key_label
183
+ ##
184
+ # inserts an application label at given index
185
+ # to add the key, use create_datakeys to add bindings
186
+ # remember to call restore_application_key_labels after updating/inserting
187
+ def insert_application_key_label(index, display_code, text)
188
+ @repaint_required = true
189
+ labels = key_labels()
190
+ labels.insert(index, [display_code , text] )
191
+ end
192
+ # ADD HERE KEYLABEL
193
+ end
194
+ end
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env ruby
2
+ # ----------------------------------------------------------------------------- #
3
+ # File: listbox.rb
4
+ # Description: A list box based on textpad
5
+ # Author: jkepler http://github.com/mare-imbrium/canis/
6
+ # Date: 2014-04-06 - 19:37
7
+ # License: Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
8
+ # Last update: 2014-07-07 00:36
9
+ # ----------------------------------------------------------------------------- #
10
+ # listbox.rb Copyright (C) 2012-2014 kepler
11
+
12
+ require 'canis'
13
+ require 'forwardable'
14
+ require 'canis/core/include/listselectionmodel'
15
+ ##
16
+ # A listbox based on textpad.
17
+ # Contains a scrollable array of Strings. The list is selectable too.
18
+ # In place editing is not provided, however editing in a separate box
19
+ # has been implemented in various examples.
20
+ # Essentially, the listbox only adds selection to the textpad.
21
+ # TODO
22
+ # ----
23
+ # [ ] focussed_color - this could be part of textpad too. row under cursor
24
+ # [ ] rlist has menu actions that can use prompt menu or popup ?
25
+ # [ ] nothing has been done about show_selector -- consider whether to knock off
26
+ #
27
+ #
28
+ # CHANGES
29
+ # -------
30
+ # - removed Array operations to Textpad, some renaming 2014-04-10 - 20:50
31
+ #
32
+ #
33
+ module Canis
34
+
35
+ ##
36
+ # A scrollable, selectable array of strings.
37
+ # Delegates display to ListRenderer
38
+ # Delegates selection to Defaultlistselection (/include/listselectionmodel.rb)
39
+ # Due to extending Defaultlistselection, methods are not visible here.
40
+ # Selection methods are (the first three are what programmers will use the most):
41
+ #
42
+ # - `selected_values` : returns values selecteda (multiple selection)
43
+ # - `selected_value` : returns value of row selected (single selection)
44
+ # - `selected_rows` : same as selected_indices, indices of selected items
45
+ #
46
+ # - `toggle_row_selection` : toggles current row, called by key $row_selector
47
+ # - `select` : select given or current row
48
+ # - `unselect` : unselects given or current row
49
+ # - `is_row_selected?` : determine if given row is selected
50
+ # - `is_selection_empty?` : has anything been selected
51
+ # - `clear_selection` : clear selection
52
+ # - `select_all` : select all rows
53
+ #
54
+ # Listbox also fires a ListSelectionEvent whose type can be:
55
+ #
56
+ # - :INSERT , a row or rows added to selection
57
+ # - :DELETE , a row or rows removed from selection
58
+ # - :CLEAR , all selection cleared
59
+ #
60
+ # == Examples
61
+ #
62
+ # mylist = %w[john tim matz shougo _why sean aaron]
63
+ # l = Listbox.new @form, :row => 5, :col => 4, :height => 10, :width => 20, :list => mylist
64
+ #
65
+ # Inside a Flow:
66
+ #
67
+ # lb = listbox :list => mylist, :title => 'Contacts', :width_pc => 50, :selection_mode => :single
68
+ #
69
+ class Listbox < TextPad
70
+
71
+ extend Forwardable
72
+
73
+ # boolean, should a selector character be shown on the left of data for selected rows.
74
+ dsl_property :show_selector
75
+ # should textpads content_cols also add left_margin ? XXX
76
+ # how much space to leave on left, currently 0, was used with selector character once
77
+ dsl_property :left_margin
78
+
79
+ # justify text to :left :right or :center (renderer to take care of this).
80
+ dsl_accessor :justify
81
+
82
+ # should focussed line be shown in a different way, currently BOLD, default true
83
+ dsl_accessor :should_show_focus
84
+
85
+ def initialize form = nil, config={}, &block
86
+
87
+ @left_margin = 0
88
+ @should_show_focus = true
89
+
90
+ register_events([:LEAVE_ROW, :LIST_SELECTION_EVENT])
91
+ self.extend DefaultListSelection
92
+ super
93
+ # textpad takes care of enter_row and press
94
+ #@_events.push(*[:LEAVE_ROW, :LIST_SELECTION_EVENT])
95
+ bind_key(?f, 'next row starting with char'){ set_selection_for_char(nil) }
96
+
97
+ # if user has not specified a selection model, install default
98
+ unless @selection_mode == :none
99
+ unless @list_selection_model
100
+ create_default_selection_model
101
+ end
102
+ end
103
+ # if user has not specified a renderer, install default
104
+ unless @renderer
105
+ create_default_renderer
106
+ end
107
+ end
108
+ # create a default renderer since user has not specified
109
+ # Widgets inheriting this with a differernt rendering such as tree
110
+ # can overrider this.
111
+ def create_default_renderer
112
+ r = ListRenderer.new self
113
+ renderer(r)
114
+ end
115
+ def renderer *val
116
+ if val.empty?
117
+ return @renderer
118
+ end
119
+ @renderer = val[0]
120
+ end
121
+ # create a default selection model
122
+ # Widgets inheriting this may override this
123
+ def create_default_selection_model
124
+ list_selection_model(Canis::DefaultListSelectionModel.new self)
125
+ end
126
+
127
+
128
+ # http://www.opensource.apple.com/source/gcc/gcc-5483/libjava/javax/swing/table/DefaultTableColumnModel.java
129
+ #
130
+ # clear the list completely of data, including selections
131
+ def clear
132
+ @selected_indices.clear
133
+ super
134
+ end
135
+ alias :remove_all :clear
136
+
137
+ # This is called whenever user leaves a row
138
+ # Fires handler for leave_row
139
+ def on_leave_row arow
140
+ # leave this out, since we are not painting on exit of widget 2014-07-02 - 17:51
141
+ #if @should_show_focus
142
+ #fire_row_changed arow
143
+ #end
144
+ fire_handler :LEAVE_ROW, self
145
+ end
146
+ # This is called whenever user enters a row
147
+ def on_enter_row arow
148
+ super
149
+ # TODO check if user wants focus to be showed
150
+ ## this results in the row being entered and left being evaluated and repainted
151
+ # which means that the focussed row can be bolded. The renderer's +render+ method will be triggered
152
+ if @should_show_focus
153
+ fire_row_changed @oldindex
154
+ fire_row_changed arow
155
+ end
156
+ end
157
+ #def on_leave
158
+ #super
159
+ #on_leave_row @current_index if @current_index
160
+ #end
161
+ # get a char ensure it is a char or number
162
+ # In this state, it could accept control and other chars.
163
+ private
164
+ def _ask_a_char
165
+ ch = @graphic.getch
166
+ #message "achar is #{ch}"
167
+ if ch < 26 || ch > 255
168
+ @graphic.ungetch ch
169
+ return :UNHANDLED
170
+ end
171
+ return ch.chr
172
+ end
173
+ public
174
+ # sets the selection to the next row starting with char
175
+ # Trying to return unhandled is having no effect right now. if only we could pop it into a
176
+ # stack or unget it.
177
+ def set_selection_for_char char=nil
178
+ char = _ask_a_char unless char
179
+ return :UNHANDLED if char == :UNHANDLED
180
+ #alert "got #{char}"
181
+ @oldrow = @current_index
182
+ @last_regex = /^#{char}/i
183
+ ix = next_regex @last_regex
184
+ return unless ix
185
+ @current_index = ix[0]
186
+ #alert "curr ind #{@current_index} "
187
+ @search_found_ix = @current_index
188
+ @curpos = ix[1]
189
+ ensure_visible
190
+ return @current_index
191
+ end
192
+ # Find the next row that contains given string
193
+ # @return row and col offset of match, or nil
194
+ # @param String to find
195
+ def next_regex str
196
+ first = nil
197
+ ## content can be string or Chunkline, so we had to write <tt>index</tt> for this.
198
+ ## =~ does not give an error, but it does not work.
199
+ @list.each_with_index do |line, ix|
200
+ col = line =~ /#{str}/
201
+ if col
202
+ first ||= [ ix, col ]
203
+ if ix > @current_index
204
+ return [ix, col]
205
+ end
206
+ end
207
+ end
208
+ return first
209
+ end
210
+
211
+ end # class listbox
212
+
213
+
214
+ ## Takes care of rendering the list.
215
+ # In the case of a List we take care of selected indices.
216
+ # Also, focussed row is shown in bold, although we can make that optional and configurable
217
+ # A user wanting a different rendering of listboxes may either extend this class
218
+ # or completely replace it and set it as the renderer.
219
+ class ListRenderer < AbstractTextPadRenderer
220
+ # text to be placed in the left margin. This requires that a left margin be set in the source
221
+ # object.
222
+ attr_accessor :left_margin_text
223
+ attr_accessor :row_focussed_attr
224
+
225
+ def initialize source
226
+ @source = source
227
+ # internal width based on both borders - earlier internal_width which we need
228
+ @int_w = 3
229
+ # 3 leaves a blank black in popuplists as in testlistbox.rb F4
230
+ # setting it as 2 means that in some cases, the next line first character
231
+ # gets overwritten with traversal
232
+ #@int_w = 2
233
+ end
234
+ # This is called prior to render_all, and may not be called when a single row is rendered
235
+ # as in fire_row_changed
236
+ def pre_render
237
+ super
238
+ @selected_indices = @source.selected_indices
239
+ @left_margin = @source.left_margin
240
+ @bg = @source.bgcolor
241
+ @fg = @source.color
242
+ @attr = NORMAL
243
+ @row_focussed_attr ||= $row_focussed_attr
244
+ end
245
+
246
+ #
247
+ # @param pad for calling print methods on
248
+ # @param lineno the line number on the pad to print on
249
+ # @param text data to print
250
+ #--
251
+ # NOTE: in some cases like testlistbox.rb if a line is updated then the newly printed
252
+ # value may not overwrite the entire line, addstr seems to only write the text no more
253
+ # Fixed with +clear_row+
254
+ #++
255
+ def render pad, lineno, text
256
+ sele = false
257
+ =begin
258
+ bg = @source.bgcolor
259
+ fg = @source.color
260
+ att = NORMAL
261
+ cp = get_color($datacolor, fg, bg)
262
+ =end
263
+ bg = @bg || @source.bgcolor
264
+ fg = @fg || @source.color
265
+ att = @attr || NORMAL
266
+ cp = get_color($datacolor, fg, bg)
267
+
268
+ if @selected_indices.include? lineno
269
+ # print selected row in reverse
270
+ sele = true
271
+ fg = @source.selected_color || fg
272
+ bg = @source.selected_bgcolor || bg
273
+ att = @source.selected_attr || REVERSE
274
+ cp = get_color($datacolor, fg, bg)
275
+ elsif lineno == @source.current_index
276
+ # print focussed row in different attrib
277
+ if @source.should_show_focus
278
+ # bold was supposed to be if the object loses focus, but although render is called
279
+ # however, padrefresh is not happening since we do not paint on exiting a widget
280
+ att = BOLD
281
+ if @source.focussed
282
+ att = @row_focussed_attr
283
+ end
284
+ end
285
+ # take current index into account as BOLD
286
+ # and oldindex as normal
287
+ end
288
+ FFI::NCurses.wattron(pad,FFI::NCurses.COLOR_PAIR(cp) | att)
289
+ FFI::NCurses.mvwaddstr(pad, lineno, 0, @left_margin_text) if @left_margin_text
290
+ FFI::NCurses.mvwaddstr(pad, lineno, @left_margin, text)
291
+ FFI::NCurses.wattroff(pad,FFI::NCurses.COLOR_PAIR(cp) | att)
292
+
293
+ # the above only sets the attrib under the text not the whole line, we
294
+ # need the whole line to be REVERSE
295
+ # Strangely in testlistbox1 unselecting removes the entire lines REVERSE
296
+ # but in testlistbox.rb the previous selected lines REV only partially goes
297
+ # so we have to make the entire line in current attrib
298
+ sele = true
299
+ if sele
300
+ FFI::NCurses.mvwchgat(pad, y=lineno, x=@left_margin, @source.width - @left_margin - @int_w, att, cp, nil)
301
+ end
302
+ end
303
+ # clear row before writing so previous contents are erased and don't show through
304
+ # I could do this everytime i write but trying to make it faster
305
+ # and only call this if +fire_row_changed+ is called.
306
+ # NOTE: in clear_row one is supposed to clear to the width of the pad, not window
307
+ # otherwise on scrolling you might get black bg if you have some other color bg.
308
+ # This is mostly important if you have a bgcolor that is different from the terminal
309
+ # bgcolor.
310
+ # @param - pad
311
+ # @param - line number (index of row to clear)
312
+ def _clear_row pad, lineno
313
+ raise "unused"
314
+ @color_pair ||= get_color($datacolor, @source.color, @source.bgcolor)
315
+ cp = @color_pair
316
+ att = NORMAL
317
+ @_clearstring ||= " " * (@source.width - @left_margin - @int_w)
318
+ # with int_w = 3 we get that one space in popuplist
319
+ # added attr on 2014-05-02 - 00:16 otherwise a list inside a white bg messagebox shows
320
+ # empty rows in black bg.
321
+ FFI::NCurses.wattron(pad,FFI::NCurses.COLOR_PAIR(cp) | att)
322
+ FFI::NCurses.mvwaddstr(pad,lineno, @left_margin, @_clearstring)
323
+ FFI::NCurses.wattroff(pad,FFI::NCurses.COLOR_PAIR(cp) | att)
324
+ end
325
+ end
326
+ end # module