class Canis::TextArea

a multiline text editing widget

TODO - giving data to user - adding newlines, and withog adding.

- respect newlines for incoming data
we need a set_text method, passing nil or blank clears
current way is not really good. remove_all sucks.
 TODO don't set maxlen if nil. compute it as a local in methods. Else splitpane will not
 work correctly.

Attributes

overwrite_mode[RW]

dsl_accessor :suppress_borders # added 2010-02-12 12:21 values true or false

toprow[R]

Public Class Methods

new(form = nil, config={}) click to toggle source
Calls superclass method
# File lib/canis/core/widgets/extras/rtextarea.rb, line 53
def initialize form = nil, config={}, &block
  @focusable = true
  @editable = true
  @row = 0
  @col = 0
  @curpos = 0
  @list = []
  @suppress_borders = false
  @row_offset = @col_offset = 1 # for cursor display on first entry, so not positioned on border
  @_events ||= [] 
  @_events.push :CHANGE
  super
  @orig_col = @col
  # this does result in a blank line if we insert after creating. That's required at
  # present if we wish to only insert
  if @list.empty?
  #  @list << "\r"   # removed this on 2009-02-15 17:25 lets see how it goes
  end
  @content_rows = @list.length
  @win = @graphic # 2009-12-26 14:54 BUFFERED  replace form.window with graphic
  # 2010-01-10 19:35 compute locally if not set
  install_keys
  init_vars
  bordertitle_init
  init_actions
end

Public Instance Methods

<<(data) click to toggle source

wraps line sent in if longer than _maxlen Typically a line is sent in. We wrap and put a hard return at end.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 139
def << data
  # if width if nil, either set it, or add this to a container that sets it before calling this method
  _maxlen = @maxlen || @width - @internal_width
  if data.length > _maxlen
    #$log.debug "wrapped append for #{data}"
    data = wrap_text data
    #$log.debug "after wrap text for :#{data}"
    data = data.split("\n")
    # 2009-01-01 22:24 the \n was needed so we would put a space at time of writing.
    # we need a soft return so a space can be added when pushing down.
    # commented off 2008-12-28 21:59
    #data.each {|line| @list << line+"\n"}
    data.each {|line| @list << line}
     @list[-1] << "\r" #XXXX
  else
    #$log.debug "normal append for #{data}"
    data << "\r" if data[-1,1] != "\r" #XXXX
    @list << data
  end
  set_modified  # added 2009-03-07 18:29
  goto_end if @auto_scroll 
  self
end
OLDprint_borders() click to toggle source

private

# File lib/canis/core/widgets/extras/rtextarea.rb, line 182
    def OLDprint_borders
      window = @graphic # 2009-12-26 14:54 BUFFERED
      @color_pair = get_color($datacolor) # 2011-09-28 V1.3.1
      bordercolor = @border_color || @color_pair
      borderatt = @border_attrib || Ncurses::A_NORMAL
      #color = $datacolor
      #window.print_border @row, @col, @height, @width, color
      window.print_border @row, @col, @height-1, @width, bordercolor, borderatt
      print_title
=begin
      hline = "+%s+" % [ "-"*(width-((1)*2)) ]
      hline2 = "|%s|" % [ " "*(width-((1)*2)) ]
      window.printstring( row=startrow, col=startcol, hline, color)
      print_title
      (startrow+1).upto(startrow+height-1) do |row|
        window.printstring(row, col=startcol, hline2, color)
      end
      window.printstring(startrow+height, col=startcol, hline, color)
=end
  
    end
OLDprint_title() click to toggle source

private

# File lib/canis/core/widgets/extras/rtextarea.rb, line 204
def OLDprint_title
  # truncate title if longer than width
  return unless @title
  @color_pair ||= get_color($datacolor)
  _title = @title
  if @title.length > @width - 2
    _title = @title[0..@width-2]
  end
  @graphic.printstring( @row, @col+(@width-_title.length)/2, _title, @color_pair, @title_attrib) unless @title.nil?
end
Oinsert(off0, *data) click to toggle source

this avoids wrapping. Better to use the <<.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 101
def Oinsert off0, *data
  @list.insert off0, *data
  # fire_handler :CHANGE, self  # 2008-12-09 14:56  NOT SURE
end
addcol(num) click to toggle source

FIXME : these 2 only require the footer to be repainted not everything We should be able to manage that. We need a repaint_footer_required. Setting repaint_required really slows performance when one presses the right arrow key since a repaint is happenign repeatedly for each key.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 474
    def addcol num
#     @repaint_required = true # added 2010-01-15 23:59, so that footer is updated, sucks!
      @repaint_footer_required = true # 2010-01-23 22:41
      my_win = @form || @parent_component.form # 2010-02-12 12:51
      my_win.addcol num
    end
addrowcol(row,col) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 480
def addrowcol row,col
  #@repaint_required = true # added 2010-01-15 23:59
  @repaint_footer_required = true # 2010-01-23 22:41
  my_win = @form || @parent_component.form # 2010-02-12 12:51
  my_win.addrowcol row, col
end
ask_search_forward() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 898
def ask_search_forward
    regex =  get_string("Enter regex to search", 20, @last_regex||"")
    ix = _find_next regex, @current_index
    if ix.nil?
      alert("No matching data for: #{regex}")
    else
      set_focus_on(ix)
      set_form_col @find_offset
    end
end
at_eol?() click to toggle source
added 2009-10-04 22:13

returns whether cursor is at end of line

# File lib/canis/core/widgets/extras/rtextarea.rb, line 458
def at_eol?
  if @curpos+1== @list[@current_index].length  
    return  true
  end
  return false
end
at_last_line?() click to toggle source
added 2009-10-04 22:13

returns whether at last line (required so that forward does not go to start)

# File lib/canis/core/widgets/extras/rtextarea.rb, line 466
def at_last_line?
  return true if @list.length == @current_index + 1
  return false
end
buffer_len() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 430
def buffer_len
  @list[@current_index].nil? ? 0 : @list[@current_index].chomp().length  
end
current_line() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 790
def current_line
  @list[@current_index]
end
cursor_backward() click to toggle source
2009-10-04 23:01 taken care that you can't go back at start of textarea

it was going onto border

# File lib/canis/core/widgets/extras/rtextarea.rb, line 488
def cursor_backward
    #$log.debug "back char cp ll and ci #{@list.length}, #{@current_index}"
    #$log.debug "back char cb #{@curpos}, #{@buffer.length}. wi: #{@width}"
    return if @curpos == 0 and @current_index == 0 # added 2009-10-04 23:02
    repeatm { 
      if @curpos > 0
        @curpos -= 1
        addcol -1
      else # trying this out 2008-12-26 20:18
        ret = up
        cursor_eol if ret != -1
      end
    }
end
cursor_bol() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 808
def cursor_bol
  set_form_col 0
end
cursor_bounds_check() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 426
def cursor_bounds_check
  max = buffer_len()
  @curpos = max if @curpos > max # check 2008-12-27 00:02
end
cursor_eol() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 803
def cursor_eol
   _maxlen = @maxlen || @width - @internal_width
  $log.error "ERROR !!! bufferlen gt _maxlen #{@buffer.length}, #{_maxlen}" if @buffer.length > _maxlen
  set_form_col current_line().chomp().length() #-1 needs to be one ahead 2011-10-10 TRYING OUT XXX
end
cursor_forward(num=1) click to toggle source

FIXME : if cursor at end of last line then forward takes cursor to start of last line (same line), should stop there.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 440
def cursor_forward num=1
  #$log.debug "next char cp #{@curpos}, #{@buffer.length}. wi: #{@width}"
  #$log.debug "next char cp ll and ci #{@list.length}, #{@current_index}"
  #if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
  return if at_eol? and at_last_line?
  repeatm { 
  if @curpos < buffer_len()
    @curpos += 1
    addcol 1
  else # trying this out 2008-12-26 20:18
    @curpos = 0
    down 1 # if not then multipler will trigger there too
  end
  cursor_bounds_check
  }
end
do_current_row() { |list| ... } click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 433
def do_current_row # :yields current row
  yield @list[@current_index]
  @buffer = @list[@current_index]
end
do_relative_row(num) { |list| ... } click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 793
def do_relative_row num
  yield @list[@current_index+num] 
end
edit_external() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 920
def edit_external
  require 'canis/core/include/appmethods'
  require 'tempfile'
  f = Tempfile.new("canis")
  l = self.text
  l.each { |line| f.puts line }
  fp = f.path
  f.flush

  editor = ENV['EDITOR'] || 'vi'
  vimp = %x[which #{editor}].chomp
  ret = shell_out "#{vimp} #{fp}"
  if ret
    lines = File.open(f,'r').readlines
    set_content(lines, :content_type => @old_content_type)
  end
end
get_content() click to toggle source

FOR scrollable ###

# File lib/canis/core/widgets/extras/rtextarea.rb, line 225
def get_content
  @list
end
get_text() click to toggle source

def to_s this was just annoying in debugs

# File lib/canis/core/widgets/extras/rtextarea.rb, line 812
def get_text
  l = getvalue
  str = ""
  old = " "
  l.each_with_index do |line, i|
    tmp = line.gsub("\n","")
    tmp.gsub!("\r", "\n")
    if old[-1,1] !~ /\s/ and tmp[0,1] !~ /\s/
      str << " "
    end
    str << tmp
    old = tmp
  end
  str
end
get_window() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 266
def get_window
  @graphic
end
getvalue() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 276
def getvalue
  @list
end
handle_key(ch) click to toggle source

textarea

# File lib/canis/core/widgets/extras/rtextarea.rb, line 327
def handle_key ch
  @current_key = ch # I need some funcs to know what key they were mapped to
  @buffer = @list[@current_index]
  if @buffer.nil? and @list.length == 0
    ## 2009-10-04 22:39
    # what this newline does is , if we use << to append, data is appended
    # to second line
    @list << "\n" # changed space to newline so wrapping puts a line.
    @current_index = 0 ; ## added 2009-10-04 21:47
    @buffer = @list[@current_index]
  end
  ## 2009-10-04 20:48  i think the next line was resulting in a hang if buffer nil
  # in sqlc on pressing Clear.
  # if buffer is nil and user wants to enter something -- added UNHANDLED
  return :UNHANDLED if @buffer.nil?
  #$log.debug "TA: before: curpos #{@curpos} blen: #{@buffer.length}"
  # on any line if the cursor is ahead of buffer length, ensure its on last position
  # what if the buffer is somehow gt maxlen ??
  if @curpos > @buffer.length
    addcol(@buffer.length-@curpos)+1
    @curpos = @buffer.length
  end
  #$log.debug "TA: after : curpos #{@curpos} blen: #{@buffer.length}, w: #{@width} max #{@maxlen}"
  
  #NOTE C-d being used for del what of scroll !!
  case ch
  when KEY_ENTER, KEY_RETURN, FFI::NCurses::KEY_ENTER # numeric enter
    insert_break
  #when ?\C-u.getbyte(0)
    ## since textareas are editable we use a control key to increase
    ## multiplier. Series is 4 16 64
    #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
    #return 0
  else
    #$log.debug(" textarea ch #{ch}")
    ret = putc ch
    if ret == :UNHANDLED
      # check for bindings, these cannot override above keys since placed at end
      ret = process_key ch, self
      #$log.debug "TA process_key #{ch} got ret #{ret} in #{@name} "
      return :UNHANDLED if ret == :UNHANDLED
    end
  end
  set_form_row
  set_form_col  # testing 2008-12-26 19:37
  $multiplier = 0 # reset only if key handled
  return 0
end
init_actions() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 954
def init_actions
  editor = ENV['EDITOR'] || 'vi'
  am = action_manager()
  am.add_action(Action.new("&Edit in #{editor} ") { edit_external })
  am.add_action(Action.new("&Saveas") { saveas() } )
end
init_vars() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 79
def init_vars
  @repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41
  @toprow = @current_index = @pcol = 0
  @repaint_all=true 
  @row_offset = @col_offset = 0 if @suppress_borders
  @longest_line = 0
  # if borders used, reduce 2 from width else 0
  @internal_width = 2
  @internal_width = 2 if @suppress_borders # WHAT THE !!!! It should be zero
  bind_key(?\M-w, :kill_ring_save)
  bind_key(?\C-y, :yank)
  bind_key(?\M-y, :yank_pop)
  bind_key(?\M-\C-w, :append_next_kill)
  map_keys
end
insert(off0, data) click to toggle source

trying to wrap and insert

# File lib/canis/core/widgets/extras/rtextarea.rb, line 114
def insert off0, data
   _maxlen = @maxlen || @width - @internal_width
  if data.length > _maxlen
    data = wrap_text data
  #  $log.debug "after wrap text done :#{data}"
    data = data.split("\n")
    data[-1] << "\r" #XXXX
  data.each do |row|
    @list.insert off0, row
    off0 += 1
  end
  else
    data << "\r" if data[-1,1] != "\r" #XXXX
    @list.insert off0, data
  end
  # expecting array !!
  #data.each do |row|
    #@list.insert off0, row
    #off0 += 1
  #end
  #$log.debug " AFTER INSERT: #{@list}"
end
insert_break() click to toggle source

FIXME - fire event not correct, not undo'ing correctly, check row and also slash r append

# File lib/canis/core/widgets/extras/rtextarea.rb, line 393
def insert_break
  return -1 unless @editable
  # insert a blank row and append rest of this line to cursor
  $log.debug "ENTER PRESSED at  #{@curpos}, on row #{@current_index}"
  @delete_buffer = (delete_eol || "")
  @list[@current_index] << "\r"
  $log.debug "DELETE BUFFER #{@delete_buffer}" 
  @list.insert @current_index+1, @delete_buffer 
  @curpos = 0
  down
  col = @orig_col + @col_offset
  setrowcol @row+1, col
  # FIXME maybe this should be insert line since line inserted, not just data, undo will delete it
  fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT_LINE, @current_index, @delete_buffer)     #  2008-12-24 18:34
end
insert_wrap(lineno, pos, lastchars) click to toggle source

this attempts to recursively insert into a row, seeing that any stuff exceeding is pushed down further. Yes, it should check for a para end and insert. Currently it could add to next para.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 686
def insert_wrap lineno, pos, lastchars
   _maxlen = @maxlen || @width - @internal_width
  @list[lineno].insert pos, lastchars 
  len = @list[lineno].length 
  if len > _maxlen
      push_last_word lineno #- sometime i may push down 10 chars but the last word is less
    end
end
join_to_prev_line() click to toggle source

private when backspace pressed in position zero if the previous line is filled we may have to bring down the last word and join, rather than go up FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space, reverse to find last space. Lop off all after space and replace this line with that balance. UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this

# File lib/canis/core/widgets/extras/rtextarea.rb, line 508
    def join_to_prev_line
      return -1 unless @editable
      return if @current_index == 0
      oldcurpos = @curpos
      oldprow = @current_index
      prev = @list[@current_index-1].chomp
      prevlen = prev.length
      # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
      if prevlen == 0
        delete_line @current_index-1
        up
        return
      end
      _maxlen = @maxlen || @width - @internal_width
      space_left = _maxlen - prevlen
      # prev line is full exit
      return if space_left == 0

      # get last space, if none, return
      blank_found = @buffer.rindex(' ', space_left)
      return unless blank_found # no word in the space i can carry up.
      # get string for carrying up
      carry_up = @buffer[0..blank_found]
      result = @list[@current_index-1].chomp! # this has to be undone too.
      @list[@current_index-1] << carry_up
      #$log.debug "carry up: #{carry_up} prevrow:#{@list[@current_index -1]}"
      # remove from curr line
      @list[@current_index].slice!(0..carry_up.length-1)
      $log.debug "carry up: #{carry_up} currrow:#{@list[@current_index]}"
      #@list[@current_index] ||= ""
      up
      addrowcol -1,0
      @curpos = prevlen
      # if result not nil, then we need that to be recorded FIXME
      fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+carry_up.length, self, :DELETE, oldprow, carry_up)
      fire_handler :CHANGE, InputDataEvent.new(prevlen,prevlen+carry_up.length, self, :INSERT, oldprow-1, carry_up)

      ## BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
      #carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
      #if carry_up.nil?
        ## carry down last word
        #prev_wd = remove_last_word @current_index-1
        ## 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
        #if !prev_wd.nil?
           #@buffer.insert 0, prev_wd
           #@curpos = prev_wd.length
           #$log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
           #fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd)     #  2008-12-26 23:07
        #end
      #else
        #$log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
        #@list[@current_index-1]=prev + carry_up
        #space_left2 = @buffer[(carry_up.length+1)..-1]
        #@list[@current_index]=space_left2 #if !space_left2.nil?
        #@list[@current_index] ||= ""
        #up
        #addrowcol -1,0
        #@curpos = prevlen
        #fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up)     #  2008-12-24 18:34
        #fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up)     #  2008-12-24 18:34
      #end
      ## FIXME -- can;t have a naked for reference here.
      ##@form.col = @orig_col + @col_offset + @curpos
      col1 = @orig_col + @col_offset + @curpos
      setrowcol nil, col1 # 2010-02-12 13:09  RFED16

#     $log.debug "carry up: nil" if carry_up.nil?
#     $log.debug "listrow nil " if @list[@current_index].nil?
#     $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
    end
kill_line() click to toggle source

mimicking emacs behavior of C-k. delete entire line if at start, else delete till eol

# File lib/canis/core/widgets/extras/rtextarea.rb, line 314
def kill_line
    # i'ved added curpos == 0 since emacs deletes a line if cursor is at 0
    # Earlier behavior was based on alpine which leaves a blank line
    if @editable
      if @buffer.chomp == "" || @curpos == 0
        delete_line
      else
        delete_eol 
      end
    end
end
map_keys() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 280
def map_keys
  return if @keys_mapped
  @key_map = :both # get both vim and emacs keys
  require 'canis/core/include/listbindings'
  bindings
  #
  # There's one issue, if using vim keys, most of them won't
  # work in text area. So you will need emacs keys in text area.

  # moved to listbin
  #bind_key(Ncurses::KEY_LEFT){ cursor_backward }
  #bind_key(Ncurses::KEY_RIGHT){ cursor_forward }
  #bind_key(Ncurses::KEY_UP){ ret = up;  get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW }
  # the next was irritating if user wanted to add a row ! 2011-10-10
  ##bind_key(Ncurses::KEY_DOWN){ ret = down ; get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW }
  #bind_key(Ncurses::KEY_DOWN){ ret = down ; }

  bind_key(KEY_BACKSPACE){ delete_prev_char if @editable }
  bind_key(KEY_BSPACE){ delete_prev_char if @editable}
  bind_key(?\M-d, :delete_word)
  bind_key(?\M-f, :forward_word)

  # earlier 330
  bind_key(FFI::NCurses::KEY_DC, 'delete current char'){ delete_curr_char if @editable }
  bind_key(?\C-k, 'kill line'){ kill_line }
  bind_key(?\C-_, 'undo'){ undo }
  bind_key(?\C-r, 'redo') { text_redo }
  #bind_key(27){ set_buffer @original_value }
  #bind_key([?\C-x, ?e], :edit_external)
  #bind_key([?\C-x, ?\C-s], :saveas)
  @keys_mapped = true
end
move_char_up() click to toggle source

move up one char from next row to current, used when deleting in a line should not be called if line ends in “r”

# File lib/canis/core/widgets/extras/rtextarea.rb, line 769
def move_char_up
  @list[@current_index] << @list[@current_index+1].slice!(0)
  delete_line(@current_index+1) if next_line().length==0
end
move_chars_up() click to toggle source

tries to move up as many as possible should not be called if line ends in “r”

# File lib/canis/core/widgets/extras/rtextarea.rb, line 775
def move_chars_up
  oldprow = @current_index
  oldcurpos = @curpos
   _maxlen = @maxlen || @width - @internal_width
  space_left = _maxlen - @buffer.length
  can_move = [space_left, next_line.length].min
  carry_up =  @list[@current_index+1].slice!(0, can_move)
  @list[@current_index] << carry_up
  delete_line(@current_index+1) if next_line().length==0
  fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+can_move, self, :INSERT, oldprow, carry_up)     #  2008-12-24 18:34
end
next_line() click to toggle source

returns next line, does not move to it,

# File lib/canis/core/widgets/extras/rtextarea.rb, line 787
def next_line
  @list[@current_index+1]
end
old_join_to_prev_line() click to toggle source

private when backspace pressed in position zero if the previous line is filled we may have to bring down the last word and join, rather than go up FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space, reverse to find last space. Lop off all after space and replace this line with that balance. UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this

# File lib/canis/core/widgets/extras/rtextarea.rb, line 584
    def old_join_to_prev_line
      return -1 unless @editable
      return if @current_index == 0
      oldcurpos = @curpos
      oldprow = @current_index
      prev = @list[@current_index-1].chomp
      prevlen = prev.length
      # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
      if prevlen == 0
        delete_line @current_index-1
        up
        return
      end
      _maxlen = @maxlen || @width - @internal_width
      space_left = _maxlen - prev.length
      # BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
      carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
      if carry_up.nil?
        # carry down last word
        prev_wd = remove_last_word @current_index-1
        # 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
        if !prev_wd.nil?
           @buffer.insert 0, prev_wd
           @curpos = prev_wd.length
           $log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
           fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd)     #  2008-12-26 23:07
        end
      else
        $log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
        @list[@current_index-1]=prev + carry_up
        space_left2 = @buffer[(carry_up.length+1)..-1]
        @list[@current_index]=space_left2 #if !space_left2.nil?
        @list[@current_index] ||= ""
        up
        addrowcol -1,0
        @curpos = prevlen
        fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up)     #  2008-12-24 18:34
        fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up)     #  2008-12-24 18:34
      end
      # FIXME -- can;t have a naked for reference here.
      #@form.col = @orig_col + @col_offset + @curpos
      col1 = @orig_col + @col_offset + @curpos
      setrowcol nil, col1 # 2010-02-12 13:09  RFED16

#     $log.debug "carry up: nil" if carry_up.nil?
#     $log.debug "listrow nil " if @list[@current_index].nil?
#     $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
    end
paint() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 839
def paint
  # not sure where to put this, once for all or repeat 2010-02-12 RFED16
  #my_win = @form? @form.window : @target_window
  #$log.warn "neither form not target window given!!! TA paint 751" unless my_win
  raise "height or width nil h:#{@height} , w: #{@width} " if @height.nil? || @width.nil?
  raise "graphic is nil in textarea paint()" unless @graphic
  print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
  rc = row_count
  _maxlen = @maxlen || @width-@internal_width # TODO fix in other branches remove ||=
  $log.debug " #{@name} textarea repaint width is #{@width}, height is #{@height} , maxlen #{_maxlen}/ #{@maxlen}, #{@graphic.name} "
  tm = get_content
  tr = @toprow
  acolor = get_color $datacolor
  h = scrollatrow()
  r,c = rowcol
  @longest_line = @width # _maxlen scroll uses width not maxlen
  $log.debug " TA:::: #{tr} , #{h}, r #{r} c #{c} "
  0.upto(h) do |hh|
    crow = tr+hh
    if crow < rc
        #focussed = @current_index == crow ? true : false
        #selected = is_row_selected crow
      content = tm[crow].chomp rescue ""
        content.gsub!(/\t/, '  ') # don't display tab
        content.gsub!(/[^[:print:]]/, '')  # don't display non print characters
        if !content.nil? 
          if content.length > _maxlen # only show _maxlen
            @longest_line = content.length if content.length > @longest_line
            ## added nil check since we are allowing scrolling in listscrollable anyway 2013-03-06 - 00:14
            content = content[@pcol..@pcol+_maxlen-1] || " "
          else
            ## added nil check since we are allowing scrolling in listscrollable anyway
            content = content[@pcol..-1] || " "
          end
        end
        #renderer = get_default_cell_renderer_for_class content.class.to_s
        #renderer = cell_renderer()
        #renderer.repaint @form.window, r+hh, c+(colix*11), content, focussed, selected
        #renderer.repaint @form.window, r+hh, c, content, focussed, selected
        @graphic.printstring  r+hh, c, "%-*s" % [@width-@internal_width,content], acolor, @attr
        if @search_found_ix == tr+hh
          if !@find_offset.nil?
            @graphic.mvchgat(y=r+hh, x=c+@find_offset, @find_offset1-@find_offset, Ncurses::A_NORMAL, $reversecolor, nil)
          end
        end

    else
      # clear rows
        # TODO the spaces string can be stored once outside loop
      @graphic.printstring r+hh, c, " " * (@width-@internal_width), acolor,@attr
    end
  end
  show_caret_func

  @table_changed = false
  @repaint_required = false
  @repaint_footer_required = true # 2010-01-23 22:41
  @repaint_all = false # added 2010-01-14 for redrawing everything
end
print_foot() click to toggle source

text_area print footer

push_last_word(lineno=@current_index) click to toggle source

push the last word from given line to next I have modified it to push all words that are exceeding maxlen. This was needed for if i push 10 chars to next line, and the last word is less then the line will exceed. So i must push as many words as exceed length. 2010-09-07 22:31 this must not return nil, or previous will crash. This happens if no space in line.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 650
def push_last_word lineno=@current_index
   _maxlen = @maxlen || @width - @internal_width
  #lastspace = @buffer.rindex(" ")
  #lastspace = @list[lineno].rindex(/ \w/)
  line = @list[lineno]
  line = @list[lineno][0.._maxlen+1] if line.length > _maxlen
  lastspace = line.rindex(/ \w/)
  $log.debug " PUSH:2 #{lastspace},#{line},"
  # fix to ensure something returned 2010-09-07 22:40
  lastspace = _maxlen-1 unless lastspace # added 2010-09-07 22:29  XXXX

  if !lastspace.nil?
    lastchars = @list[lineno][lastspace+1..-1]
    @list[lineno] = @list[lineno][0..lastspace]
    $log.debug "PUSH_LAST:ls:#{lastspace},lw:#{lastchars},lc:#{lastchars[-1]},:#{@list[lineno]}$"
    if lastchars[-1,1] == "\r" or @list[lineno+1].nil?
      # open a new line and keep the 10 at the end.
      append_row lineno, lastchars
    else
      # check for soft tab \n - NO EVEN THIS LOGIC IS WRONG.
      #if lastchars[-1,1] == "\n"
      if lastchars[-1,1] != ' ' and @list[lineno+1][0,1] !=' '
        #@list[lineno+1].insert 0, lastchars + ' '
        insert_wrap lineno+1, 0, lastchars + ' '
      else
        #@list[lineno+1].insert 0, lastchars
        insert_wrap lineno+1, 0, lastchars 
      end
    end
    return lastchars, lastspace
  end
  return nil
end
putc(c) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 747
def putc c
  if c >= 32 and c <= 126
    begin
      ret = putch c.chr
    rescue => ex
      # this does not prevent entry, it prevents updating
      # often comes here if error in event block, not our fault
      Ncurses.beep
      $log.debug " ERROR IN PUTCH RTEXTAREA  "
      $log.debug( ex) if ex
      $log.debug(ex.backtrace.join("\n")) if ex
    end
    if ret == 0
    # addcol 1
      set_modified 
      return 0
    end
  end
  return :UNHANDLED
end
putch(char) click to toggle source

add one char. careful, i shoved a string in yesterday.

# File lib/canis/core/widgets/extras/rtextarea.rb, line 696
def putch char
   _maxlen = @maxlen || @width - @internal_width
  @buffer ||= @list[@current_index]
  return -1 if !@editable #or @buffer.length >= _maxlen
  #if @chars_allowed != nil # remove useless functionality
    #return if char.match(@chars_allowed).nil?
  #end
  raise "putch expects only one char" if char.length != 1
  oldcurpos = @curpos
  #$log.debug "putch : pr:#{@current_index}, cp:#{@curpos}, char:#{char}, lc:#{@buffer[-1]}, buf:(#{@buffer})"
  if @overwrite_mode
    @buffer[@curpos] = char
  else
    @buffer.insert(@curpos, char)
  end
  @curpos += 1 
  #$log.debug "putch INS: cp:#{@curpos}, max:#{_maxlen}, buf:(#{@buffer.length})"
  if @curpos-1 > _maxlen or @buffer.length()-1 > _maxlen
    lastchars, lastspace = push_last_word @current_index
    #$log.debug "last sapce #{lastspace}, lastchars:#{lastchars},lc:#{lastchars[-1]}, #{@list[@current_index]} "
    ## wrap on word XX If last char is 10 then insert line
    @buffer = @list[@current_index]
    if @curpos-1 > _maxlen  or @curpos-1 > @buffer.length()-1
      ret = down 
      # keep the cursor in the same position in the string that was pushed down.
      @curpos = oldcurpos - lastspace  #lastchars.length # 0
    end
  end
  set_form_row
  @buffer = @list[@current_index]
  set_form_col
  @modified = true
  fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :INSERT, @current_index, char)     #  2008-12-24 18:34
  @repaint_required = true
  0
end
remove_last_word(lineno) click to toggle source

removes and returns last word in given line number, or nil if no whitespace

# File lib/canis/core/widgets/extras/rtextarea.rb, line 733
def remove_last_word lineno
  @list[lineno].chomp!
  line=@list[lineno]
  lastspace = line.rindex(" ")
  if !lastspace.nil?
    lastchars = line[lastspace+1..-1]
    @list[lineno].slice!(lastspace..-1)
    $log.debug " remove_last: lastspace #{lastspace},#{lastchars},#{@list[lineno]}"
    fire_handler :CHANGE, InputDataEvent.new(lastspace,lastchars.length, self, :DELETE, lineno, lastchars)     #  2008-12-26 23:06
    return lastchars
  end
  return nil
end
repaint() click to toggle source

FOR scrollable ###

# File lib/canis/core/widgets/extras/rtextarea.rb, line 270
def repaint # textarea
  #return unless @repaint_required # 2010-02-12 19:08  TRYING - won't let footer print if only col move
  @graphic = @form.window unless @graphic # print_border not getting it 2014-08-30 - 20:41
  paint if @repaint_required
  print_foot if @print_footer && !@suppress_borders && (@repaint_footer_required || @repaint_required)
end
row_count() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 836
def row_count
  @list.size
end
rowcol() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 95
def rowcol
#  $log.debug "textarea rowcol : #{@row+@row_offset+@winrow}, #{@col+@col_offset}"
  return @row+@row_offset, @col+@col_offset
end
saveas(name=nil, config={}) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 937
def saveas name=nil, config={}
  unless name
    name = rb_gets "File to save as: "
    return if name.nil? || name == ""
  end
  exists = File.exists? name
  if exists # need to prompt
    return unless rb_confirm("Overwrite existing file? ")
  end
  l = getvalue
  File.open(name, "w"){ |f|
    l.each { |line| f.puts line }
    #l.each { |line| f.write line.gsub(/\r/,"\n") }
  }
  rb_puts "#{name} written."
end
scrollatrow() click to toggle source

alias :get_text :to_s

---- for listscrollable ---- ##
# File lib/canis/core/widgets/extras/rtextarea.rb, line 829
def scrollatrow
  if @suppress_borders
    @height - 1 
  else
    @height - 3 
  end
end
set_content(lines, config={}) click to toggle source

sets content of textarea. I don't know why this was not existing all this while Name to be consistent with textview. Okay, this does not wrap the words, we assume its short enough. FIXME. Avoid using currently till i firm this. NOTE: does not wrap, and does not trigger events Added on 2011-10-10 @since 1.4.0 @param [String, Array] String is an existing filename, Array is content to be replaced Added config for compatibility with textview

# File lib/canis/core/widgets/extras/rtextarea.rb, line 237
def set_content lines, config={}
  case lines
  when String
    if File.exists? lines
      lines = File.open(lines,"r").readlines
    else
      raise "set_content String param should be a filename"
    end
  when Array
  else
    raise "Don't know how to handle data in set_content: #{lines.class} "
  end
  @list.replace lines
  @repaint_required = true
end
set_form_col(col1=@curpos) click to toggle source

set cursor on correct column

# File lib/canis/core/widgets/extras/rtextarea.rb, line 409
def set_form_col col1=@curpos
  @curpos = col1
  @cols_panned ||= 0
  cursor_bounds_check
  
  ## added win_col on 2009-12-28 20:21 for embedded forms BUFFERED TRYING OUT
  win_col = 0 # 2010-02-07 23:19 new cursor stuff
  #col = win_col + @orig_col + @col_offset + @curpos
  #col = win_col + @orig_col + @col_offset + @curpos + @cols_panned
  # 2010-01-14 13:31 changed orig_col to col for embedded forms, splitpanes.
  col = win_col + @col + @col_offset + @curpos + @cols_panned
  $log.debug "sfc: wc:#{win_col}  col:#{@col}, coff:#{@col_offset}. cp:#{@curpos} colsp:#{@cols_panned} . "
  #@form.setrowcol @form.row, col   # added 2009-12-29 18:50 BUFFERED
  $log.debug " TA calling setformrow col nil, #{col} "
  setrowcol nil, col   # added 2009-12-29 18:50 BUFFERED
  @repaint_footer_required = true
end
set_modified(tf=true) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 796
def set_modified tf=true
  @modified = tf
  @repaint_required = tf
  @repaint_footer_required = tf
  # 2010-01-14 22:45 putting a check for form, so not necessary to have form set when appending data
  @form.modified = true if tf and !@form.nil?
end
text(*val) click to toggle source

alias :text :set_content

set text
Added for consistency with other widgets
# File lib/canis/core/widgets/extras/rtextarea.rb, line 255
def text(*val)
  if val.empty?
    return @list
  end
  set_content(*val)
  self
end
text=(val) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 262
def text=(val)
  return unless val # added 2010-11-17 20:11, dup will fail on nil
  set_content(val)
end
text_redo() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 915
def text_redo
  return unless @undo_handler
  @undo_handler.redo
end
undo() click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 908
def undo
  if @undo_handler
    @undo_handler.undo
  else
    undo_delete
  end
end
undo_delete() click to toggle source

this is broken, delete_buffer could be a line or a string or array of lines

# File lib/canis/core/widgets/extras/rtextarea.rb, line 376
def undo_delete
    # added 2008-11-27 12:43  paste delete buffer into insertion point
    return if @delete_buffer.nil?
    $log.warn "undo_delete is broken! perhaps cannot be used . textarea 347 "
    # FIXME - can be an array
    case @delete_buffer
    when Array
      # we need to unroll array, and it could be lines not just a string
      str = @delete_buffer.first
    else
      str = @delete_buffer
    end
    @buffer.insert @curpos, str 
    set_modified 
    fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT, @current_index, @delete_buffer)     #  2008-12-24 18:34
end
words_in_length(buff, len) click to toggle source

return as many words as fit into len for carrying up.. actually there is a case of when the next char (len+1) is a white space or word boundary. XXX

# File lib/canis/core/widgets/extras/rtextarea.rb, line 635
def words_in_length buff, len
  return nil if len == 0
  str = buff[0..len]
  ix = str.rindex(/\s/)
  $log.debug " str #{str} len #{len} ix #{ix} , buff #{buff}~"
  return nil if ix.nil?
  ix = ix > 0 ? ix - 1 : ix
  $log.debug " str[]:#{str[0..ix]}~ len #{len} ix #{ix} , buff #{buff}~"
  return str[0..ix]
end
wrap_para(line=@current_index) click to toggle source
# File lib/canis/core/widgets/extras/rtextarea.rb, line 162
def wrap_para line=@current_index
  line ||= 0
  l=[]
  while true
    if @list[line].nil? or @list[line]=="" or @list[line]==13 #"\r"
      break
    end
    #$log.debug "lastchar #{@list[line][-1]}, appending: #{@list[line]}]"
    t =  @list[line]
    l << t.strip
    @list.delete_at line
    break if t[-1]==13 # "\r"
#    line += 1
  end
  str=l.join(" ")
  #$log.debug " sending insert : #{str}."
  insert line, str
end
wrap_text(txt, col = @maxlen) click to toggle source

private

# File lib/canis/core/widgets/extras/rtextarea.rb, line 106
def wrap_text(txt, col = @maxlen)
   col ||= @width - @internal_width
  #$log.debug "inside wrap text for :#{txt}"
  txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
           "\\1\\3\n") 
end