Class: RubyCurses::ScrollPane

Inherits:
Widget show all
Defined in:
lib/rbcurse/rscrollpane.rb

Overview

A scrollable box throgh which one can see portions of underlying object such as textarea, table or a form, usually the underlying data is larger than what can be displayed.

Constant Summary

Constants included from Io

Io::ERROR_COLOR_PAIR, Io::FOOTER_COLOR_PAIR, Io::LINEONE, Io::MAIN_WINDOW_COLOR_PAIR

Instance Attribute Summary collapse

Attributes inherited from Widget

#_object_created, #col_offset, #cols_panned, #config, #curpos, #focussed, #form, #id, #parent_component, #row_offset, #rows_panned, #state

Instance Method Summary collapse

Methods inherited from Widget

#changed, #click, #destroy, #enter, #event_list, #focus, #get_preferred_size, #getvalue_for_paint, #height=, #hide, #leave, #modified?, #move, #on_leave, #override_graphic, #printstring, #process_key, #remove, #repaint_all, #repaint_required, #set_buffer_modified, #set_buffering, #set_form, #set_modified, #setformrowcol, #setrowcol, #show, #text_variable, #unbind_key, #width=

Methods included from Io

#askchoice, #askyesno, #askyesnocancel, #clear_error, #clear_this, #get_string, #newaskyesno, #old_print_header, #old_print_top_right, #print_action, #print_error, #print_footer_help, #print_header, #print_headers, #print_help, #print_help_page, #print_in_middle, #print_key_labels, #print_key_labels_row, #print_screen_labels, #print_status, #print_this, #print_top_right, #rbgetstr, #warn

Methods included from Utils

#_process_key, #bind_key, #clean_string!, #get_color, #keycode_tos, #repeatm, #view, #wrap_text

Methods included from ConfigSetup

#cget, #config_setup, #configure, #variable_set

Methods included from EventHandler

#bind, #fire_handler, #fire_property_change

Constructor Details

#initialize(form, config = {}, &block) ⇒ ScrollPane

Returns a new instance of ScrollPane.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rbcurse/rscrollpane.rb', line 57

def initialize form, config={}, &block
  @focusable = true
  @editable = false
  #@left_margin = 1
  @row = 0
  @col = 0
  super
  @row_offset = @col_offset = 1
  init_vars
  @_events.push :STATE_CHANGE
#  $log.debug " SCROLLPANE recvs form #{form.name}, #{form.window.name} " unless form.nil?


end

Instance Attribute Details

#cascade_changesObject

viewport row_viewport column_viewport horizontal scrollbar 0-NONE, 1=ALWAYS, 2=AS_NEEDED vertical scrollbar 0-NONE, 1=ALWAYS, 2=AS_NEEDED



55
56
57
# File 'lib/rbcurse/rscrollpane.rb', line 55

def cascade_changes
  @cascade_changes
end

Instance Method Details

#_downObject

private



352
353
354
# File 'lib/rbcurse/rscrollpane.rb', line 352

def _down
  increment_view_row(1)
end

#_upObject

private



356
357
358
# File 'lib/rbcurse/rscrollpane.rb', line 356

def _up
  increment_view_row(-1)
end

#child(ch) ⇒ Object

set child component being used in viewport

See Also:



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rbcurse/rscrollpane.rb', line 74

def child ch
  if ch != nil
    @child = ch # added 2010-02-11 15:28 we might do away with viewport, setting panned to child
    @child.rows_panned = @child.cols_panned = 0

    ch.parent_component = self # added 2010-01-13 12:55 so offsets can go down ?

    @child.should_create_buffer = true 
    @form.add_rows += 2 # related to scr_top  XXX What if form not set. i cannot keep accumulating
    update_child
    # -3 since we start row +1 to get indented by 1, also we use
    # height -1 in scrollpane, so we need -2 to indent, and one more
    # for row
    set_viewport_view(ch)
  end
end

#cursor_backwardObject



362
363
364
# File 'lib/rbcurse/rscrollpane.rb', line 362

def cursor_backward
  increment_view_col(-1)
end

#cursor_forwardObject



359
360
361
# File 'lib/rbcurse/rscrollpane.rb', line 359

def cursor_forward
  increment_view_col(1)
end

#downObject



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/rbcurse/rscrollpane.rb', line 365

def down
  ## scroll down one row (currently one only)
  $log.debug " MULT DOWN #{$multiplier} "
  repeatm {
  ret = _down
  return unless ret # 2010-02-04 18:29 
  ## we've scrolled down, but we need  to keep the cursor where
  ##+ editing actually is. Isn't this too specific to textarea ?
  $log.debug " SCRP setting row to #{@form.row-1} upon scrolling down  "
  ## only move up the cursor if its within bounds
  #       if @form.row > @row
  @child.rows_panned = @child.rows_panned-1  if ret 
  @form.setrowcol @form.row-1+@row_outofbounds, @form.col if ret 
  }
end

#get_viewportObject

return underlying viewport in order to run some of its methods



159
160
161
# File 'lib/rbcurse/rscrollpane.rb', line 159

def get_viewport
  return @viewport
end

#getvalueObject



263
264
265
# File 'lib/rbcurse/rscrollpane.rb', line 263

def getvalue
  # TODO
end

#h_scroll_barObject



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/rbcurse/rscrollpane.rb', line 437

def h_scroll_bar
  return if @viewport.nil?
  sz = (@viewport.width*1.00/@viewport.child().width)*@viewport.width
  #$log.debug " h_scroll_bar sz #{sz}, #{@viewport.width} #{@viewport.child().width}" 
  sz = sz.ceil
  return if sz < 1
  start = 1
  start = ((@viewport.col*1.00+@viewport.width)/@viewport.child().width)*@viewport.width
  start -= sz
  start = start.ceil
  # # the problem with next 2 lines is that attributes of border could be overwritten
  # draw horiz line
  r = @row #+ @ext_row_offset # 2010-02-11 11:57 RFED16
  c = @col #+ @ext_col_offset # 2010-02-11 11:57 RFED16
  $log.debug " h_scroll_bar start #{start}, r #{r} c #{c} h:#{@height} "
  @graphic.rb_mvwhline(r+@height-1, c+1, FFI::NCurses::ACS_HLINE, @width-2)
  # draw scroll bar
  #sz.times{ |i| @graphic.mvaddch(r+@height-1, c+start+1+i, FFI::NCurses::ACS_CKBOARD) }
  sz.times{ |i| @graphic.rb_mvaddch(r+@height-1, c+start+1+i, FFI::NCurses::ACS_CKBOARD) }
end

#handle_key(ch) ⇒ Object

handle keys for scrollpane. First hands key to child object If unused, checks to see if it has anything mapped. If not consumed, returns :UNHANDLED, else 0.



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/rbcurse/rscrollpane.rb', line 270

def handle_key ch
  # if this gets key it should just hand it to child
    return :UNHANDLED if @viewport.nil? # added 2010-02-02 12:44 
  if @viewport != nil
    $log.debug "    calling child handle_key #{ch} "
    ret = @viewport.handle_key ch
    # XXX ret returns 0under normal circumstance, so will next line work ?
    # what i mean is if ret == 0
    
    @repaint_required = true if ret == 0  # added 2009-12-27 22:21 BUFFERED
    $log.debug "  ... child ret #{ret}"


    ## Here's the only option scrollpane has of checking whether the child has
    ##+ exceeded boundary BUFFERED 2009-12-29 23:12 
    #  TEMPORARILY COMMENTED WHILE TESTING SCROLL UP AND DOWN XXX
    #fr = @form.row
    #fc = @form.col
    #if fr >= @row + @height -2
      #@form.setrowcol @row + @height -2, fc
    #elsif fr < @row
      #@form.setrowcol @row, fc
    #end
    #if fc >= @col + @width -1
      #@form.setrowcol fr, @col + @width -1
    #end
    ##

    return ret if ret != :UNHANDLED
  end
  ret = 0 # default return value
  ks = keycode_tos(ch)
  $log.debug " scrollpane gets KEY #{ch}, ks #{ks} "
  case ch
    when ?\M-n.getbyte(0)
      ## scroll down one row (unless multiplier set)
      ret = down
  when ?\M-p.getbyte(0)
      ## scroll up one row (unless multiplier set)
    ret = up
  #when ?0.getbyte(0), ?\C-[.getbyte(0)
    #goto_start #start of buffer # cursor_start
  #when ?\C-].getbyte(0)
    #goto_end # end / bottom cursor_end # TODO
  when ?\M-\<.getbyte(0)
    @height.times { up ; }
  when ?\M-\>.getbyte(0)
    @height.times { down ; }
  when KEY_DOWN
    ret = down
    #check_curpos
  when  ?\M-h.getbyte(0)
    ## scroll left one position
    repeatm {
      ret = cursor_backward
      @child.cols_panned = @child.cols_panned+1  if ret
      @form.setrowcol @form.row, @form.col+1+@col_outofbounds if ret 
    }
  when  ?\M-l.getbyte(0)
    ## scroll right one position
    repeatm {
      ret = cursor_forward
      @child.cols_panned = @child.cols_panned-1  if ret
      @form.setrowcol @form.row, @form.col-1+@col_outofbounds if ret 
    }
  when KEY_BACKSPACE, KEY_BSPACE
    ret = cursor_backward
  #when ?\C-u.getbyte(0)
    ## multiplier. Series is 4 16 64
    #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
    #return 0
  when ?\C-c.getbyte(0)
    $multiplier = 0
    return 0
  else
    return :UNHANDLED
  end
  ret = :UNHANDLED if !ret
  $multiplier = 0
  return ret # 0 2010-02-04 18:47 returning ret else repaint is happening when UNHANDLED
end

#height(*val) ⇒ Object

set height a container must pass down changes in size to it’s children

2010-02-04 18:06 - i am not sure about this. When viewport is set then it passes down 
changes to child which user did not intend. Maybe in splitpane it is okay but other cases?
Perhaps its okay if scrollpane gets larger than child, not otherwise.

added 2010-01-16 23:55



485
486
487
488
489
490
491
492
493
494
495
# File 'lib/rbcurse/rscrollpane.rb', line 485

def height(*val)
    return @height if val.empty?
    oldvalue = @height || 0
    super
    @height = val[0]
    return if @viewport == nil
    delta = @height - oldvalue
    return if delta == 0
    @repaint_required = true
    @viewport.height += delta
end

#increment_view_col(num) ⇒ true, false

Returns false if r,c not changed.

Returns:

  • (true, false)

    false if r,c not changed



222
223
224
225
226
227
228
229
230
# File 'lib/rbcurse/rscrollpane.rb', line 222

def increment_view_col num
  r, c = @viewport.get_pad_top_left()
  #r = @viewport.row() #- @viewport.top_margin
  #c = @viewport.col() #- @viewport.left_margin
  c += num
  ret = set_view_position r, c
  h_scroll_bar if ret
  return ret
end

#increment_view_row(num) ⇒ true, false

Returns false if r,c not changed.

Returns:

  • (true, false)

    false if r,c not changed



211
212
213
214
215
216
217
218
219
220
# File 'lib/rbcurse/rscrollpane.rb', line 211

def increment_view_row num
#x      r = @viewport.row() #- @viewport.top_margin
#x      c = @viewport.col() #- @viewport.left_margin
  r, c = @viewport.get_pad_top_left()
  $log.debug " SCR inc viewport currently :  r #{r} c #{c} "
  r += num
  ret = set_view_position r, c
  v_scroll_bar if ret
  return ret
end

#init_varsObject



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rbcurse/rscrollpane.rb', line 134

def init_vars
  #@curpos = @pcol = @toprow = @current_index = 0
  @hsb_policy = :AS_NEEDED
  @vsb_policy = :AS_NEEDED
  @repaint_required = true
  @repaint_border = true
  @row_outofbounds=0
  @col_outofbounds=0
  @border_width = 2
  @screen_top = 0
  @screen_left = 0
end

#on_enterObject



391
392
393
394
# File 'lib/rbcurse/rscrollpane.rb', line 391

def on_enter
  #super 2010-01-02 18:53 leading to a stack overflow XXX ???
  set_form_row
end

#paintObject



433
434
435
436
# File 'lib/rbcurse/rscrollpane.rb', line 433

def paint
  @repaint_required = false
  @repaint_all = false
end

#repaintObject

scrollpane



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/rbcurse/rscrollpane.rb', line 231

def repaint # scrollpane
  # viewports child should repaint onto pad
  # viewport then clips
  # this calls viewports refresh from its refresh
  return unless @repaint_required
  if @viewport
    update_child
    $log.debug "SCRP  #{@name} calling viewport repaint"
    #@viewport.repaint_all true # 2010-01-16 23:09 
    @viewport.repaint_required true # changed 2010-01-19 19:34 
    @viewport.repaint # child's repaint should do it on its pad
    $log.debug " #{@name}  SCRP scrollpane repaint #{@graphic.name} "
  end
    # TODO this only if major change
   if @repaint_border && @repaint_all # added 2010-01-16 20:15 
    #@graphic.wclear
    $log.debug " #{@name} repaint all scroll: r #{@row} c #{@col}  h  #{@height}-1 w #{@width} "
    bordercolor = @border_color || $datacolor
    borderatt = @border_attrib || Ncurses::A_NORMAL
    # NOTE - should be width-1 print_b reduces one from width, but
    # not height !

    @graphic.print_border_only(@row, @col, @height-1, @width, bordercolor, borderatt)
    h_scroll_bar
    v_scroll_bar
#x XXX       @viewport.repaint_all(true) unless @viewport.nil? # brought here 2010-01-19 19:34 
    #@repaint_border = false # commented off on 2010-01-16 20:15 so repaint_all can have effect
   end
  return if @viewport == nil
  $log.debug "SCRP   #{@name} calling viewport to SCRP  b2s #{@graphic.name}  "
  paint 
end

#rowcolObject

this is called once only, on select_field by form. + after that not at all.



423
424
425
426
427
428
429
430
431
# File 'lib/rbcurse/rscrollpane.rb', line 423

def rowcol
  r1 = @row #+@row_offset
  c1 = @col #+@col_offset
  return r1, c1 if @viewport.nil? # added 2010-02-02 12:41 

  r,c = @viewport.child.rowcol # added 2009-12-28 15:23 BUFFERED
  $log.debug "SCRP rowcol:  #{r1} + #{r} , #{c1} + #{c} "
  return r1+r, c1+c
end

#set_columnheader_view(ch) ⇒ Object

sets the component to be used as a column header TODO



177
178
179
180
181
182
# File 'lib/rbcurse/rscrollpane.rb', line 177

def set_columnheader_view ch
  old = @columnheader
  @columnheader = Viewport.new
  @columnheader.set_view ch
  fire_property_change "column_header", old, @columnheader
end

#set_form_colObject

added 2010-02-09 10:17 Sometimes some parent objects may just call this. Would be better if they only called row and row called both ??? or is that less reliable In any case we have to combine this someday!!



411
412
413
414
415
416
417
418
419
# File 'lib/rbcurse/rscrollpane.rb', line 411

def set_form_col
  #@form.row = @row + 1 unless @form.nil?
  if @viewport != nil
    #$log.debug "    calling scrollpane set_form_row"
    ret = @viewport.child.set_form_col # added 2010-01-16 21:09 
  end
  $log.debug " FORM SCRP #{@form.name} "
  $log.debug "SCRP set_form_col #{@form.row}  #{@form.col} "
end

#set_form_rowObject

this is called once externally, on on_enter + after that its called internally only, which in this case is never



397
398
399
400
401
402
403
404
405
406
# File 'lib/rbcurse/rscrollpane.rb', line 397

def set_form_row
  #@form.row = @row + 1 unless @form.nil?
  if @viewport != nil
    #$log.debug "    calling scrollpane set_form_row"
    ret = @viewport.child.set_form_row # added 2009-12-27 23:23 BUFFERED
    ret = @viewport.child.set_form_col # added 2010-01-16 21:09 
  end
  $log.debug " FORM SCRP #{@form.name} "
  $log.debug "SCRP set_form_row #{@form.row}  #{@form.col} "
end

#set_rowheader_view(ch) ⇒ Object

sets the component to be used as a rowheader TODO



170
171
172
173
174
175
# File 'lib/rbcurse/rscrollpane.rb', line 170

def set_rowheader_view ch
  old = @rowheader
  @rowheader = Viewport.new
  @rowheader.set_view ch
  fire_property_change "row_header", old, @rowheader
end

#set_view_position(r, c) ⇒ Object

seems i wrote this only so i could set repaint_required to true However, now that VP calls state changed, that will happen XXX



192
193
194
195
196
197
198
199
# File 'lib/rbcurse/rscrollpane.rb', line 192

def set_view_position r,c
  ret = @viewport.set_view_position r,c
  if ret
    @repaint_required = true if ret 
#    fire_property_change("view_position", 
  end
  return ret
end

#set_view_size(h, w) ⇒ Object



183
184
185
186
187
188
189
# File 'lib/rbcurse/rscrollpane.rb', line 183

def set_view_size h,w
  # calling the property shoudl uniformally trigger fire_property_change
  @viewport.set_view_size h,w
  #height(h)
  #width(w)
  #fire_handler :PROPERTY_CHANGE, self # XXX should it be an event STATE_CHANGED with details
end

#set_viewport(vp) ⇒ Object

Directly set the viewport. Usually it is best to use set_viewport_view instead



164
165
166
167
168
# File 'lib/rbcurse/rscrollpane.rb', line 164

def set_viewport vp
  old = @viewport
  @viewport = vp
  fire_property_change "viewport", old, @viewport
end

#set_viewport_view(ch) ⇒ Object

set the component to be viewed



147
148
149
150
151
152
153
154
155
156
# File 'lib/rbcurse/rscrollpane.rb', line 147

def set_viewport_view ch
  @viewport = Viewport.new nil
  @viewport.set_view ch
  ## this -2 should depend on whether we are putting border/scrollbars or not.
  # -1 added on 2010-02-16 23:35 since we are red 1, and bw
  @viewport.set_view_size(@height-@border_width-0, @width-@border_width-0) # XXX make it one less
  @viewport.cascade_changes = @cascade_changes # added 2010-02-04 18:19 
  @viewport.bind(:STATE_CHANGE) { |e| view_state_changed(e) }
  @viewport.bind(:PROPERTY_CHANGE) { |e| view_property_changed(e) }
end

#upObject



380
381
382
383
384
385
386
387
388
389
390
# File 'lib/rbcurse/rscrollpane.rb', line 380

def up
      ## scroll up one row (currently one only)
  repeatm {
    ret = _up
    return unless ret # 2010-02-04 18:29 
    $log.debug " SCRP setting row to #{@form.row+1} upon scrolling up R:#{@row} H:#{@height}  "
   #     if @form.row < @row + @height
      @child.rows_panned = @child.rows_panned+1  if ret 
      @form.setrowcol @form.row+1+@row_outofbounds, @form.col if ret 
  }
end

#update_childObject

update of child’s coordinates, needs to be called whenever it changes, so i need to call it before calling child’s update FIXME - this is become 2 calls, make it one - becoming expensive if called often



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rbcurse/rscrollpane.rb', line 95

def update_child
  scr_top = 3 # for Pad, if Pad passed as in SplitPane
  scr_left = 1 # for Pad, if Pad passed as in SplitPane
  if @form.window.window_type == :WINDOW
    scr_top = @row + 1
    scr_left = @col + 1
    @child.row(@row+@row_offset)
    @child.col(@col+@col_offset)
  else
    # PAD case
    @child.row(scr_top)
    @child.col(scr_left)
  end
    @child.set_buffering(:target_window => @target_window || @form.window, :form => @form, :bottom => @height-3, :right => @width-3 )
    @child.set_buffering(:screen_top => scr_top, :screen_left => scr_left)
    # lets set the childs ext offsets
    $log.debug "SCRP #{name} adding (to #{@child.name}) ext_row_off: #{@child.ext_row_offset} +=  #{@ext_row_offset} +#{@row_offset}  "
    $log.debug "SCRP adding ext_col_off: #{@child.ext_col_offset} +=  #{@ext_col_offset} +#{@col_offset}  "
    ## 2010-02-09 18:58 i think we should not put col_offset since the col
    ## of child would take care of that. same for row_offset. XXX 
    @child.ext_col_offset += @ext_col_offset + @col + @col_offset - @screen_left # 2010-02-09 19:14 
    # added row and col setting to child RFED16 2010-02-17 00:22 as
    # in splitpane. seems we are not using ext_offsets now ? texta
    # and TV are not. and i've commented off from widget

    $log.debug " #{@child.ext_row_offset} +=  #{@ext_row_offset} + #{@row} -#{@screen_top}  "
    @child.ext_row_offset +=  @ext_row_offset  + @row   + @row_offset - @screen_top 
    # adding this since child's ht should not be less. or we have a
    # copywin failure
    @child.height ||= @height
    @child.width ||= @width
    if @child.height < @height
      @child.height = @height
    end
    if @child.width < @width
      @child.width = @width
    end

end

#v_scroll_barObject



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/rbcurse/rscrollpane.rb', line 457

def v_scroll_bar
    return if @viewport.nil?
  sz = (@viewport.height*1.00/@viewport.child().height)*@viewport.height
  #$log.debug " v_scroll_bar sz #{sz}, #{@viewport.width} #{@viewport.child().width}" 
  sz = sz.ceil
  return if sz < 1
  start = 1 
  start = ((@viewport.row*1.00+@viewport.height)/@viewport.child().height)*@viewport.height
  start -= sz
  r = @row #+ @ext_row_offset # 2010-02-11 11:57 RFED16
  c = @col #+ @ext_col_offset # 2010-02-11 11:57 RFED16
  $log.debug " v_scroll_bar start #{start}, col:#{@col} w:#{@width}, r #{r}+1 c #{c}+w-1 " 
  start = start.ceil
  # # the problem with next 2 lines is that attributes of border could be overwritten
  # draw verti line
  # this is needed to erase previous bar when shrinking
  #@graphic.mvwvline(r+1,c+@width-1, FFI::NCurses::ACS_VLINE, @height-2)
  @graphic.rb_mvwvline(r+1,c+@width-1, FFI::NCurses::ACS_VLINE, @height-2)
  # draw scroll bar
  #sz.times{ |i| @graphic.mvaddch(r+start+1+i, c+@width-1, FFI::NCurses::ACS_CKBOARD) }
  sz.times{ |i| @graphic.rb_mvaddch(r+start+1+i, c+@width-1, FFI::NCurses::ACS_CKBOARD) }
end

#view_property_changed(ev) ⇒ Object

this method is registered with Viewport for changes to properties



206
207
208
209
# File 'lib/rbcurse/rscrollpane.rb', line 206

def view_property_changed ev
  fire_handler :PROPERTY_CHANGE, ev #???
  @repaint_required = true
end

#view_state_changed(ev) ⇒ Object

this method is registered with Viewport for changes



201
202
203
204
# File 'lib/rbcurse/rscrollpane.rb', line 201

def view_state_changed ev
  fire_handler :STATE_CHANGE, ev #???
  @repaint_required = true
end

#width(*val) ⇒ Object

set width a container must pass down changes in size to it’s children added 2010-01-16 23:55



499
500
501
502
503
504
505
506
507
508
509
# File 'lib/rbcurse/rscrollpane.rb', line 499

def width(*val)
    return @width if val.empty?
    oldvalue = @width || 0
    super
    @width = val[0]
    return if @viewport == nil
    delta = @width - oldvalue
    return if delta == 0
    @repaint_required = true
    @viewport.width += delta
end