ncumbra 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,348 @@
1
+ # ----------------------------------------------------------------------------- #
2
+ # File: messagebox.rb
3
+ # Description: a small window with a list or message or fields and buttons which pops up.
4
+ # Author: j kepler http://github.com/mare-imbrium/canis/
5
+ # Date: 2018-04-13 - 23:10
6
+ # License: MIT
7
+ # Last update: 2018-04-21 14:44
8
+ # ----------------------------------------------------------------------------- #
9
+ # YFF Copyright (C) 2012-2018 j kepler
10
+ require 'umbra/window'
11
+ require 'umbra/form'
12
+ require 'umbra/widget'
13
+ require 'umbra/button'
14
+ require 'umbra/field'
15
+ require 'umbra/label'
16
+ require 'umbra/textbox'
17
+
18
+ module Umbra
19
+ class MessageBox
20
+
21
+ attr_reader :form
22
+ attr_reader :window
23
+ attr_accessor :title
24
+ attr_accessor :buttons # button labels. e.g. [Ok, Cancel]
25
+ #dsl_accessor :default_button
26
+ #
27
+ # a message to be printed, usually this will be the only thing supplied
28
+ # with an OK button. This should be a short string, a label will be used
29
+ # and input_config passed to it
30
+
31
+ #dsl_accessor :message
32
+ # you can also set button_orientation : :right, :left, :center
33
+ #
34
+ def initialize config={}, &block
35
+
36
+ h = config.fetch(:height, nil)
37
+ w = config.fetch(:width, nil)
38
+ t = config.fetch(:row, nil)
39
+ l = config.fetch(:col, nil)
40
+ if h && w && t && l
41
+ #@window = Window.new :height => h, :width => w, :top => t, :left => l
42
+ @window = Window.new h, w, t, l
43
+ # else window will be created in repaint, and form will pass it to widgets before their first
44
+ # repaint
45
+ end
46
+ @form = Form.new @window
47
+ @buttons = ["Ok", "Cancel"]
48
+
49
+ config.each_pair { |k,v| instance_variable_set("@#{k}",v) }
50
+ @config = config
51
+ @row = 0
52
+ @col = 0
53
+ @row_offset = 1
54
+ @col_offset = 2
55
+
56
+ #@color ||= :black
57
+ #@bgcolor ||= :white
58
+ @color_pair = CP_BLACK
59
+ # 2014-05-31 - 11:44 adding form color
60
+ # try not to set buttons color in this program, let button pick up user or form colors
61
+ #@form.color = @color
62
+ #@form.bgcolor = @bgcolor
63
+ #@form.color_pair = @color_pair
64
+ @maxrow = 3
65
+
66
+ instance_eval &block if block_given?
67
+ #yield_or_eval &block if block_given? TODO
68
+
69
+ end
70
+ def item widget
71
+ # # normalcolor gives a white on black stark title like links and elinks
72
+ # You can also do 'acolor' to give you a sober title that does not take attention away, like mc
73
+ # remove from existing form if set, problem with this is mnemonics -- rare situation.
74
+ #if widget.form
75
+ #f = widget.form
76
+ #f.remove_widget widget
77
+ #end
78
+ @maxrow ||= 3
79
+ #widget.set_form @form
80
+ @form.add_widget widget
81
+ widget.row ||= 0
82
+ widget.col ||= 0
83
+ if widget.row == 0
84
+ widget.row = [@maxrow+1, 3].max if widget.row == 0
85
+ else
86
+ widget.row += @row_offset
87
+ end
88
+ if widget.col == 0
89
+ widget.col = 5
90
+ else
91
+ # i don't know button_offset as yet
92
+ widget.col += @col_offset
93
+ end
94
+ # in most cases this override is okay, but what if user has set it
95
+ # The problem is that widget and field are doing a default setting so i don't know
96
+ # if user has set or widget has done a default setting. NOTE
97
+ # 2014-05-31 - 12:40 CANIS BUTTONCOLOR i have commented out since it should take from form
98
+ # to see effect
99
+ if false
100
+ widget.color ||= @color # we are overriding colors, how to avoid since widget sets it
101
+ widget.bgcolor ||= @bgcolor
102
+ widget.attr = @attr if @attr # we are overriding what user has put. DARN !
103
+ end
104
+ @maxrow = widget.row if widget.row > @maxrow
105
+ @suggested_h = @height || @maxrow+6
106
+ @suggested_w ||= 0
107
+ ww = widget.width || 5 # some widgets do no set a default width, and could be null
108
+ _w = [ww + 5, 15].max
109
+ @suggested_w = widget.col + _w if widget.col > @suggested_w
110
+ if ww >= @suggested_w
111
+ @suggested_w = ww + widget.col + 10
112
+ end
113
+ $log.debug " MESSAGEBOX add suggested_w #{@suggested_w} "
114
+ # if w's given col is > width then add to suggested_w or text.length
115
+ end
116
+ alias :add :item
117
+ # returns button index
118
+ # Call this after instantiating the window
119
+ def run
120
+ repaint
121
+ @form.pack # needs window
122
+ @form.repaint
123
+ @window.wrefresh
124
+ return handle_keys
125
+ end
126
+ def repaint
127
+ _create_window unless @window
128
+ #acolor = get_color $reverscolor, @color, @bgcolor
129
+ acolor = 0 # ??? FIXME
130
+ $log.debug " MESSAGE BOX bg:#{@bgcolor} , co:#{@color} , colorpair:#{acolor}"
131
+ @window.wbkgd(FFI::NCurses.COLOR_PAIR(acolor) | REVERSE);
132
+
133
+ @color_pair ||= CP_BLACK
134
+ bordercolor = @border_color || CP_BLACK
135
+ borderatt = @border_attrib || NORMAL
136
+ @window.wattron(FFI::NCurses.COLOR_PAIR(bordercolor) | (borderatt || FFI::NCurses::A_NORMAL))
137
+ print_border_mb @window, 1,2, @height, @width, nil, nil
138
+ @window.wattroff(FFI::NCurses.COLOR_PAIR(bordercolor) | (borderatt || FFI::NCurses::A_NORMAL))
139
+ @title ||= "+-+"
140
+ @title_color ||= CP_CYAN
141
+ @title_attr ||= REVERSE
142
+ title = " "+@title+" "
143
+ # normalcolor gives a white on black stark title like links and elinks
144
+ # You can also do 'acolor' to give you a sober title that does not take attention away, like mc
145
+ @window.printstring(@row=1,@col=(@width-title.length)/2,title, color=@title_color, @title_attr)
146
+ #print_message if @message
147
+ create_action_buttons(*@buttons) unless @action_buttons
148
+ end
149
+ def create_action_buttons *labels
150
+ @action_buttons = []
151
+ _row = @height-3
152
+ _col = (@width-(labels.count*8))/2
153
+ _col = 5 if _col < 1
154
+
155
+ labels.each_with_index do |l, ix|
156
+ b = Button.new text: l, row: _row, col: _col
157
+ _col += l.length+5
158
+ @action_buttons << b
159
+ @form.add_widget b
160
+ b.command do
161
+ @selected_index = ix
162
+ throw(:close, ix)
163
+ end
164
+ end
165
+ end
166
+ # CLEAN THIS UP TODO
167
+ # Pass a short message to be printed.
168
+ # This creates a label for a short message, and a field for a long one.
169
+ # @yield field created
170
+ # @param [String] text to display
171
+ def message message # yield label or field being used for display for further customization
172
+ @suggested_h = @height || 10
173
+ message = message.gsub(/[\n\r\t]/,' ') rescue message
174
+ message_col = 5
175
+ $log.debug " MESSAGE w: #{@width}, size: #{message.size} "
176
+ _pad = 5
177
+ @suggested_w = @width || [message.size + _pad + message_col , FFI::NCurses.COLS-2].min
178
+ r = 3
179
+ len = message.length
180
+ #@suggested_w = len + _pad + message_col if len < @suggested_w - _pad - message_col
181
+
182
+ display_length = @suggested_w-_pad
183
+ display_length -= message_col
184
+ message_height = 2
185
+ #clr = @color || :white
186
+ #bgclr = @bgcolor || :black
187
+
188
+ color_pair = CP_WHITE
189
+ # trying this out. sometimes very long labels get truncated, so i give a field in wchich user
190
+ # can use arrow key or C-a and C-e
191
+ if message.size > display_length
192
+ message_label = Field.new({:text => message, :name=>"message_label",
193
+ :row => r, :col => message_col, :width => display_length,
194
+ :color_pair => color_pair, :editable => false})
195
+ else
196
+ message_label = Label.new({:text => message, :name=>"message_label",
197
+ :row => r, :col => message_col, :width => display_length,
198
+ :height => message_height, :color_pair => color_pair})
199
+ end
200
+ @form.add_widget message_label
201
+ @maxrow = 3
202
+ yield message_label if block_given?
203
+ end
204
+ alias :message= :message
205
+
206
+ # This is for larger messages, or messages where the size is not known.
207
+ # A textview object is created and yielded.
208
+ #
209
+ def text message
210
+ @suggested_w = @width || (FFI::NCurses.COLS * 0.80).floor
211
+ @suggested_h = @height || (FFI::NCurses.LINES * 0.80).floor
212
+
213
+ message_col = 3
214
+ r = 2
215
+ display_length = @suggested_w-4
216
+ display_length -= message_col
217
+ #clr = @color || :white
218
+ #bgclr = @bgcolor || :black
219
+ color_pair = CP_WHITE
220
+
221
+ if message.is_a? Array
222
+ l = longest_in_list message
223
+ if l > @suggested_w
224
+ if l < FFI::NCurses.COLS
225
+ #@suggested_w = l
226
+ @suggested_w = FFI::NCurses.COLS-2
227
+ else
228
+ @suggested_w = FFI::NCurses.COLS-2
229
+ end
230
+ display_length = @suggested_w-6
231
+ end
232
+ # reduce width and height if you can based on array contents
233
+ else
234
+ message = wrap_text(message, display_length).split("\n")
235
+ end
236
+ # now that we have moved to textpad that +8 was causing black lines to remain after the text
237
+ message_height = message.size #+ 8
238
+ # reduce if possible if its not required.
239
+ #
240
+ r1 = (FFI::NCurses.LINES-@suggested_h)/2
241
+ r1 = r1.floor
242
+ w = @suggested_w
243
+ c1 = (FFI::NCurses.COLS-w)/2
244
+ c1 = c1.floor
245
+ @suggested_row = r1
246
+ @suggested_col = c1
247
+ brow = @button_row || @suggested_h-4
248
+ available_ht = brow - r + 1
249
+ message_height = [message_height, available_ht].min
250
+ # replaced 2014-04-14 - 23:51
251
+ message_label = Textbox.new({:name=>"message_label", :list => message,
252
+ :row => r, :col => message_col, :width => display_length,
253
+ :height => message_height, :color_pair => color_pair})
254
+ #message_label.set_content message
255
+ @form.add_widget message_label
256
+ yield message_label if block_given?
257
+
258
+ end
259
+ alias :text= :text
260
+ # returns length of longest
261
+ def longest_in_list list #:nodoc:
262
+ longest = list.inject(0) do |memo,word|
263
+ memo >= word.length ? memo : word.length
264
+ end
265
+ longest
266
+ end
267
+ def wrap_text(s, width=78) # {{{
268
+ s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n").split("\n")
269
+ end
270
+ def _create_window
271
+
272
+ $log.debug " MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
273
+ $log.debug " MESSAGEBOX _create_window h:#{@suggested_h} w:#{@suggested_w} "
274
+ @width ||= @suggested_w || 60
275
+ @height = @suggested_h || 10
276
+ $log.debug " MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
277
+ if @suggested_row
278
+ @row = @suggested_row
279
+ else
280
+ @row = ((FFI::NCurses.LINES-@height)/2).floor
281
+ end
282
+ if @suggested_col
283
+ @col = @suggested_col
284
+ else
285
+ w = @width
286
+ @col = ((FFI::NCurses.COLS-w)/2).floor
287
+ end
288
+ #@window = Window.new :height => @height, :width => @width, :top => @row, :left => @col
289
+ $log.debug " MESSAGEBOX _create_window h:#{@height} w:#{@width} r:#{@row} c:#{@col} "
290
+ @window = Window.new @height, @width, @row, @col
291
+ @graphic = @window
292
+ @form.window = @window
293
+ # in umbra, the widgets would not be having a window, if window was created after the widgets were added
294
+ end
295
+ def handle_keys
296
+ buttonindex = catch(:close) do
297
+ while((ch = @window.getch()) != FFI::NCurses::KEY_F10 )
298
+ break if ch == ?\C-q.getbyte(0) || ch == 2727 # added double esc
299
+ begin
300
+ # trying out repaint of window also if repaint all asked for. 12 is C-l
301
+ if ch == 1000 or ch == 12
302
+ repaint
303
+ end
304
+ @form.handle_key(ch)
305
+ @window.wrefresh
306
+ rescue => err
307
+ $log.debug( err) if err
308
+ $log.debug(err.backtrace.join("\n")) if err
309
+ #textdialog ["Error in Messagebox: #{err} ", *err.backtrace], :title => "Exception" # TODO
310
+ @window.refresh # otherwise the window keeps showing (new FFI-ncurses issue)
311
+ ensure
312
+ end
313
+
314
+ end # while loop
315
+ end # close
316
+ $log.debug "MESSAGEBOX: CALLING PROGRAM BEING RETURNED: #{buttonindex} "
317
+ @window.destroy
318
+ # added 2014-05-01 - 18:10 hopefully to refresh root_window.
319
+ #Window.refresh_all
320
+ return buttonindex
321
+ end
322
+ # this is identical to the border printed by dialogs.
323
+ # The border is printed not on the edge, but one row and column inside.
324
+ # This is purely cosmetic, otherwise windows.box should be used which prints a box
325
+ # on the edge.
326
+ private def print_border_mb window, row, col, height, width, color, attr # {{{
327
+ win = window.pointer
328
+ #att = attr
329
+ len = width
330
+ len = FFI::NCurses.COLS if len == 0
331
+ space_char = " ".codepoints.first
332
+ (row-1).upto(row+height-1) do |r|
333
+ # this loop clears the screen, printing spaces does not work since ncurses does not do anything
334
+ FFI::NCurses.mvwhline(win, r, col, space_char, len)
335
+ end
336
+
337
+ FFI::NCurses.mvwaddch win, row, col, FFI::NCurses::ACS_ULCORNER
338
+ FFI::NCurses.mvwhline( win, row, col+1, FFI::NCurses::ACS_HLINE, width-6)
339
+ FFI::NCurses.mvwaddch win, row, col+width-5, FFI::NCurses::ACS_URCORNER
340
+ FFI::NCurses.mvwvline( win, row+1, col, FFI::NCurses::ACS_VLINE, height-4)
341
+
342
+ FFI::NCurses.mvwaddch win, row+height-3, col, FFI::NCurses::ACS_LLCORNER
343
+ FFI::NCurses.mvwhline(win, row+height-3, col+1, FFI::NCurses::ACS_HLINE, width-6)
344
+ FFI::NCurses.mvwaddch win, row+height-3, col+width-5, FFI::NCurses::ACS_LRCORNER
345
+ FFI::NCurses.mvwvline( win, row+1, col+width-5, FFI::NCurses::ACS_VLINE, height-4)
346
+ end # }}}
347
+ end # class
348
+ end # module
data/lib/umbra/pad.rb ADDED
@@ -0,0 +1,340 @@
1
+ =begin
2
+ * Name: PadReader.rb
3
+ * Description : This is an independent file viewer that uses a Pad and traps keys
4
+ I am using only ffi-ncurses and not window.rb or any other support classes
5
+ so this can be used anywhere else.
6
+ * Author: jkepler
7
+ * Date: 2018-03-28 14:30
8
+ * License: MIT
9
+ * Last update: 2018-04-17 11:25
10
+
11
+ == CHANGES
12
+ == TODO
13
+ - should have option to wrap text
14
+ - / search ?
15
+ NOTE:
16
+ in this the cursor does not move down, it starts to scroll straight away.
17
+ So we need another version for lists and textviews in which the cursor moves with up and down.
18
+ The cursor should be invisible in this.
19
+ == -----------------------
20
+ =end
21
+ require 'ffi-ncurses'
22
+
23
+ class Pad
24
+
25
+ # You may pass height, width, row and col for creating a window otherwise a fullscreen window
26
+ # will be created. If you pass a window from caller then that window will be used.
27
+ # Some keys are trapped, jkhl space, pgup, pgdown, end, home, t b
28
+ # This is currently very minimal and was created to get me started to integrating
29
+ # pads into other classes such as textview.
30
+ def initialize config={}, &block
31
+
32
+ $log.debug " inside pad contructor"
33
+ @config = config
34
+ @rows = FFI::NCurses.LINES-1
35
+ @cols = FFI::NCurses.COLS-1
36
+ @prow = @pcol = 0 # show many cols we are panning
37
+ @startrow = 0
38
+ @startcol = 0
39
+
40
+ h = config.fetch(:height, 0)
41
+ w = config.fetch(:width, 0)
42
+ t = config.fetch(:row, 0)
43
+ l = config.fetch(:col, 0)
44
+ @color_pair = config.fetch(:color_pair, 14)
45
+ @attr = config.fetch(:attr, FFI::NCurses::A_BOLD)
46
+ @rows = h unless h == 0
47
+ @cols = w unless w == 0
48
+ @startrow = t unless t == 0
49
+ @startcol = l unless l == 0
50
+ @suppress_border = config[:suppress_border]
51
+ top = t
52
+ left = l
53
+ @height = h
54
+ @width = w
55
+ #@pointer, @panel = create_window(h, w, t, l)
56
+ @pointer, @panel = create_centered_window(h, w, @color_pair, @attr)
57
+
58
+ @startrow, @startcol = FFI::NCurses.getbegyx(@pointer)
59
+ unless @suppress_border
60
+ @startrow += 1
61
+ @startcol += 1
62
+ @rows -=3 # 3 is since print_border_only reduces one from width, to check whether this is correct
63
+ @cols -=3
64
+ end
65
+ $log.debug "top and left are: #{top} #{left} "
66
+ #@window.box # 2018-03-28 -
67
+ FFI::NCurses.box @pointer, 0, 0
68
+ title(config[:title])
69
+ FFI::NCurses.wbkgd(@pointer, FFI::NCurses.COLOR_PAIR(@color_pair) | @attr);
70
+ FFI::NCurses.curs_set 0 # cursor invisible
71
+ if config[:filename]
72
+ self.filename=(config[:filename])
73
+ elsif config[:list]
74
+ self.list=(config[:list])
75
+ end
76
+ end
77
+ # minimum window creator method, not using a class.
78
+ # However, some methods do require windows width and ht etc
79
+ def create_window h, w, t, l
80
+ pointer = FFI::NCurses.newwin(h, w, t, l)
81
+ panel = FFI::NCurses.new_panel(pointer)
82
+ FFI::NCurses.keypad(pointer, true)
83
+ return pointer, panel
84
+ end
85
+ def create_centered_window height, width, color_pair=14, attr=FFI::NCurses::A_BOLD
86
+ row = ((FFI::NCurses.LINES-height)/2).floor
87
+ col = ((FFI::NCurses.COLS-width)/2).floor
88
+ pointer = FFI::NCurses.newwin(height, width, row, col)
89
+ FFI::NCurses.wbkgd(pointer, FFI::NCurses.COLOR_PAIR(color_pair) | attr);
90
+ panel = FFI::NCurses.new_panel(pointer)
91
+ FFI::NCurses.keypad(pointer, true)
92
+ return pointer, panel
93
+ end
94
+ def destroy_window pointer, panel
95
+ FFI::NCurses.del_panel(panel) if panel
96
+ FFI::NCurses.delwin(pointer) if pointer
97
+ panel = pointer = nil # prevent call twice
98
+ end
99
+ def destroy_pad
100
+ if @pad
101
+ FFI::NCurses.delwin(@pad)
102
+ @pad = nil
103
+ end
104
+ end
105
+ # print a title over the box on zeroth row
106
+ def title stitle
107
+ return unless stitle
108
+ stitle = "| #{stitle} |"
109
+ col = (@width-stitle.size)/2
110
+ FFI::NCurses.mvwaddstr(@pointer, 0, col, stitle)
111
+ end
112
+ private def display_content content
113
+ @pad = create_pad content
114
+ FFI::NCurses.wrefresh(@pointer)
115
+ padrefresh
116
+ end
117
+
118
+ private def create_pad content
119
+ # destroy pad if exists
120
+ destroy_pad
121
+ @content_rows, @content_cols = content_dimensions(content)
122
+ pad = FFI::NCurses.newpad(@content_rows, @content_cols)
123
+ FFI::NCurses.wbkgd(pad, FFI::NCurses.COLOR_PAIR(@color_pair) | @attr);
124
+ FFI::NCurses.keypad(pad, true); # function and arrow keys
125
+
126
+ FFI::NCurses.update_panels
127
+ cp = @color_pair
128
+ #@attr = FFI::NCurses::A_BOLD
129
+ FFI::NCurses.wattron(pad, FFI::NCurses.COLOR_PAIR(cp) | @attr)
130
+ # WRITE
131
+ filler = " "*@content_cols
132
+ content.each_index { |ix|
133
+ #FFI::NCurses.mvwaddstr(pad,ix, 0, filler)
134
+ FFI::NCurses.mvwaddstr(pad,ix, 0, content[ix])
135
+ }
136
+ FFI::NCurses.wattroff(pad, FFI::NCurses.COLOR_PAIR(cp) | @attr)
137
+ return pad
138
+ end
139
+
140
+ # receive array as content source
141
+ #
142
+ def list=(content)
143
+ display_content content
144
+ end
145
+ # source of data is a filename
146
+ def filename=(filename)
147
+ content = File.open(filename,"r").read.split("\n")
148
+ display_content content
149
+ end
150
+ private def content_dimensions content
151
+ content_rows = content.count
152
+ content_cols = content_cols(content)
153
+ return content_rows, content_cols
154
+ end
155
+
156
+
157
+ # write pad onto window
158
+ private
159
+ def padrefresh
160
+ raise "padrefresh: Pad not created" unless @pad
161
+ FFI::NCurses.prefresh(@pad,@prow,@pcol, @startrow,@startcol, @rows + @startrow,@cols+@startcol);
162
+ end
163
+
164
+ # returns button index
165
+ # Call this after instantiating the window
166
+ public
167
+ def run
168
+ return handle_keys
169
+ end
170
+
171
+ # convenience method
172
+ private
173
+ def key x
174
+ x.getbyte(0)
175
+ end
176
+ def content_cols content
177
+ # FIXME bombs if content contains integer or nil.
178
+ #longest = content.max_by(&:length)
179
+ #longest.length
180
+ max = 1
181
+ content.each do |line|
182
+ next unless line
183
+ l = 1
184
+ case line
185
+ when String
186
+ l = line.length
187
+ else
188
+ l = line.to_s.length
189
+ end
190
+ max = l if l > max
191
+ end
192
+ return max
193
+ end
194
+ # returns length of longest
195
+ def longest_in_list list #:nodoc:
196
+ longest = list.inject(0) do |memo,word|
197
+ memo >= word.length ? memo : word.length
198
+ end
199
+ longest
200
+ end
201
+
202
+ # returns button index
203
+ private
204
+ def handle_keys
205
+ @height = FFI::NCurses.LINES-1 if @height == 0
206
+ ht = @rows
207
+ scroll_lines = @height/2
208
+ buttonindex = catch(:close) do
209
+ maxrow = @content_rows - @rows
210
+ maxcol = @content_cols - @cols
211
+ while ((ch = FFI::NCurses.wgetch(@pointer)) != FFI::NCurses::KEY_F10)
212
+ break if ch == ?\C-q.getbyte(0)
213
+ begin
214
+ case ch
215
+ when key(?g), 279 # home as per iterm2
216
+ @prow = 0
217
+ @pcol = 0
218
+ when key(?b), key(?G), 277 # end as per iterm2
219
+ @prow = maxrow-1
220
+ @pcol = 0
221
+ when key(?j), FFI::NCurses::KEY_DOWN
222
+ @prow += 1
223
+ when key(?k), FFI::NCurses::KEY_UP
224
+ @prow -= 1
225
+ when 32, 338 # Page Down abd Page Up as per iTerm2
226
+ @prow += 10
227
+ when key(?\C-d)
228
+ @prow += scroll_lines
229
+ when key(?\C-b)
230
+ @prow -= scroll_lines
231
+ when key(?\C-f)
232
+ @prow += ht
233
+ when key(?\C-u)
234
+ @prow -= ht
235
+ when 339
236
+ @prow -= 10
237
+ when key(?l), FFI::NCurses::KEY_RIGHT
238
+ @pcol += 1
239
+ when key(?$)
240
+ @pcol = maxcol - 1
241
+ when key(?h), FFI::NCurses::KEY_LEFT
242
+ @pcol -= 1
243
+ when key(?0)
244
+ @pcol = 0
245
+ when key(?q)
246
+ throw :close
247
+ else
248
+ #alert " #{ch} not mapped "
249
+ end
250
+ @prow = 0 if @prow < 0
251
+ @pcol = 0 if @pcol < 0
252
+ if @prow > maxrow-1
253
+ @prow = maxrow-1
254
+ end
255
+ if @pcol > maxcol-1
256
+ @pcol = maxcol-1
257
+ end
258
+ padrefresh
259
+ #FFI::NCurses::Panel.update_panels # 2018-03-28 - this bombs elsewhere
260
+ rescue => err
261
+ if $log
262
+ $log.debug err.to_s
263
+ $log.debug err.backtrace.join("\n")
264
+ end
265
+ FFI::NCurses.endwin
266
+ puts "INSIDE pad.rb"
267
+ puts err
268
+ puts err.backtrace.join("\n")
269
+ ensure
270
+ end
271
+
272
+ end # while loop
273
+ end # close
274
+ rescue => err
275
+ if $log
276
+ $log.debug err.to_s
277
+ $log.debug err.backtrace.join("\n")
278
+ end
279
+ FFI::NCurses.endwin
280
+ puts err
281
+ puts err.backtrace.join("\n")
282
+ ensure
283
+ #@window.destroy #unless @config[:window]
284
+ destroy_window @pointer, @panel
285
+ #FFI::NCurses.delwin(@pad) if @pad
286
+ destroy_pad
287
+ FFI::NCurses.curs_set 1 # cursor visible again
288
+ return buttonindex
289
+ end
290
+ end
291
+ if __FILE__ == $PROGRAM_NAME
292
+ def startup
293
+ require 'logger'
294
+ require 'date'
295
+
296
+ path = File.join(ENV["LOGDIR"] || "./" ,"v.log")
297
+ file = File.open(path, File::WRONLY|File::TRUNC|File::CREAT)
298
+ $log = Logger.new(path)
299
+ $log.level = Logger::DEBUG
300
+ today = Time.now.to_s
301
+ $log.info "Pad demo #{$0} started on #{today}"
302
+ end
303
+ def std_colors
304
+ FFI::NCurses.use_default_colors
305
+ # 2018-03-17 - changing it to ncurses defaults
306
+ FFI::NCurses.init_pair(0, FFI::NCurses::BLACK, -1)
307
+ FFI::NCurses.init_pair(1, FFI::NCurses::RED, -1)
308
+ FFI::NCurses.init_pair(2, FFI::NCurses::GREEN, -1)
309
+ FFI::NCurses.init_pair(3, FFI::NCurses::YELLOW, -1)
310
+ FFI::NCurses.init_pair(4, FFI::NCurses::BLUE, -1)
311
+ FFI::NCurses.init_pair(5, FFI::NCurses::MAGENTA, -1)
312
+ FFI::NCurses.init_pair(6, FFI::NCurses::CYAN, -1)
313
+ FFI::NCurses.init_pair(7, FFI::NCurses::WHITE, -1)
314
+ FFI::NCurses.init_pair(14, FFI::NCurses::WHITE, FFI::NCurses::CYAN)
315
+ end
316
+
317
+
318
+ FFI::NCurses.initscr
319
+ FFI::NCurses.curs_set 1
320
+ FFI::NCurses.raw
321
+ FFI::NCurses.noecho
322
+ FFI::NCurses.keypad FFI::NCurses.stdscr, true
323
+ FFI::NCurses.scrollok FFI::NCurses.stdscr, true
324
+ if FFI::NCurses.has_colors
325
+ FFI::NCurses.start_color
326
+ std_colors
327
+ end
328
+
329
+ startup
330
+ begin
331
+ file = ARGV[0] || $0
332
+ h = 20
333
+ w = 50
334
+ p = Pad.new :filename => "#{file}", :height => FFI::NCurses.LINES-1, :width => w, :row => 0, :col => 0, title: "pad.rb", color_pair: 14, attr: FFI::NCurses::A_BOLD
335
+ p.run
336
+ ensure
337
+ FFI::NCurses.endwin
338
+ FFI::NCurses.curs_set 1 # cursor visible again
339
+ end
340
+ end