
/**************************************************************************

    This file is part of Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Hector Peraza.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/

#include <limits.h>
#include <stdio.h>
#include <X11/keysym.h>
#include <X11/cursorfont.h>
#include<X11/Xatom.h>
#include "OXTextEdit.h"

void OXTextEdit::_OXTextEdit()
{
    XFontStruct *font = XLoadQueryFont(GetDisplay(),"-adobe-courier-medium-r-*-*-12-*-*-*-*-*-iso8859-1"); 
    XGCValues gcv;
    int mask = GCFont | GCForeground | GCBackground;
    unsigned long back = _client->GetColorByName("white");
    gcv.foreground = _client->GetColorByName("black");
    gcv.background = back;
    gcv.font = font->fid; 

    gcv.function = GXand;
    _gc_crs1 = XCreateGC(GetDisplay(), _canvas->GetId(), mask, &gcv);

    gcv.foreground = back;
    gcv.background = _client->GetColorByName("black");
    gcv.font = font->fid;
    Cursor defaultCursor = XCreateFontCursor(GetDisplay(), XC_xterm);
    gcv.function = GXxor;
    _gc_crs0 = XCreateGC(GetDisplay(), _canvas->GetId(), mask, &gcv);
   XDefineCursor(GetDisplay(), _canvas->GetId(), defaultCursor);
    csr_timer = new OTimer(this, 500);
    Clear();
    pasteok = False;
}


//---------------------------------------------------

OXTextEdit::OXTextEdit(OXWindow *parent, int x, int y, long id, unsigned int sboptions) :
  OXTextView(parent, x, y, id, sboptions) 
{
 _OXTextEdit();
}

//---------------------------------------------------

OXTextEdit::OXTextEdit(OXWindow *parent, int x, int y, long id, OText *text, unsigned int sboptions) :
  OXTextView(parent, x, y, id, text, sboptions) 
{
 _OXTextEdit();
}

//---------------------------------------------------

OXTextEdit::OXTextEdit(OXWindow *parent, int x, int y, long id, char *string, unsigned int sboptions) :
  OXTextView(parent, x, y, id, string, sboptions) 
{
 _OXTextEdit();
}

//---------------------------------------------------

OXTextEdit::~OXTextEdit() 
{

  delete csr_timer;     
}

//---------------------------------------------------
long OXTextEdit::ReturnLongestLineWidth()
{
 long linewidth = OXTextView::ReturnLongestLineWidth();
 linewidth+=3*_scrollVal.x;
 return linewidth;
}




//---------------------------------------------------

void OXTextEdit::Clear() 
{
    cursorstate = 1;
    _current.y = _current.x = 0;
    delete csr_timer;  
    csr_timer = new OTimer(this, 500);
    OXTextView::Clear();
}

//---------------------------------------------------

bool OXTextEdit::SaveFile(char *filename) 
{
  return _text->Save(filename);
}

//---------------------------------------------------

bool OXTextEdit::Cut()
{
 if (Copy()== False)
  return False;
 Delete();
}

//---------------------------------------------------

bool OXTextEdit::Paste()
{
 XConvertSelection(GetDisplay(), XA_PRIMARY, XA_STRING, _selProperty,
                    _id, CurrentTime);
 return True;
}

//---------------------------------------------------

bool OXTextEdit::Delete()
{
 OLongPosition pos;
 pos.y = ToObjYCoord(_visible.y);
 if (_isMarked == False)
  return False;
 _text->DelText(_markedStart, _markedEnd);
 UnMark();
 if (_markedStart.y < pos.y)
  pos.y = _markedStart.y;
 pos.x = ToObjXCoord(_visible.x, pos.y);
 if (_markedStart.x < pos.x)
  pos.x = _markedStart.x;
 SetVsbPosition((ToScrYCoord(pos.y)+_visible.y)/_scrollVal.y);
 SetHsbPosition((ToScrXCoord(pos.x, pos.y)+_visible.x)/_scrollVal.x);
 SetSBRange(HORIZONTAL);
 SetSBRange(VERTICAL);
 SetCurrent(_markedStart);
 SendMessage(_parent, MK_MSG(XC_VIEW,VIEW_ISMARKED), _ID,False);
 return True;
}

//---------------------------------------------------

bool OXTextEdit::Search(char *string, bool direction, bool caseSensitive)
{
 OLongPosition pos;
 if (_text->Search(&pos, _current, string, direction, caseSensitive) == False)
  return False;
 UnMark();
 _isMarked = True;                                                              
 _markedStart.y = _markedEnd.y = pos.y;
 _markedStart.x = pos.x;
 _markedEnd.x = _markedStart.x + strlen(string)-1;
 _markedEnd.x++;
  if (direction)
  SetCurrent(_markedEnd);
 else
  SetCurrent(_markedStart);
 _markedEnd.x--;
 pos.y = ToObjYCoord(_visible.y);
 if ((_current.y < pos.y)
        || (ToScrYCoord(_current.y) >= _canvas->GetHeight()))
  pos.y = _markedStart.y;
 pos.x = ToObjXCoord(_visible.x, pos.y);
 if ((_current.x < pos.x)
        || (ToScrXCoord(_current.x, pos.y) >= _canvas->GetWidth()))
  pos.x = _markedStart.x;

 SetVsbPosition((ToScrYCoord(pos.y)+_visible.y)/_scrollVal.y);
 SetHsbPosition((ToScrXCoord(pos.x, pos.y)+_visible.x)/_scrollVal.x);
 DrawRegion(0,ToScrYCoord(_markedStart.y),
       _canvas->GetWidth(),ToScrYCoord(_markedEnd.y+1)-ToScrYCoord(_markedEnd.y));
 return True;
}                        

//---------------------------------------------------
bool OXTextEdit::Replace(OLongPosition textPos, char *oldText, char 
*newText, bool direction,bool caseSensitive) {
 OLongPosition pos;
 if (_text->Replace(textPos, oldText, newText, direction, caseSensitive) == False)
  return False;
 UnMark();
 _isMarked = True;
 _markedStart.y = _markedEnd.y = textPos.y;
 _markedStart.x = textPos.x;
 _markedEnd.x = _markedStart.x + strlen(newText)-1;
 _markedEnd.x++;

  if (direction)
  SetCurrent(_markedEnd);
 else
  SetCurrent(_markedStart);
 _markedEnd.x--;
 pos.y = ToObjYCoord(_visible.y);
 if ((_current.y < pos.y) 
        || (ToScrYCoord(_current.y) >= _canvas->GetHeight()))
  pos.y = _markedStart.y;  
 pos.x = ToObjXCoord(_visible.x, pos.y);
 if ((_current.x < pos.x) 
        || (ToScrXCoord(_current.x, pos.y) >= _canvas->GetWidth()))
  pos.x = _markedStart.x;

 SetVsbPosition((ToScrYCoord(pos.y)+_visible.y)/_scrollVal.y);
 SetHsbPosition((ToScrXCoord(pos.x, pos.y)+_visible.x)/_scrollVal.x);
 DrawRegion(0,ToScrYCoord(_markedStart.y),
       _canvas->GetWidth(),
        ToScrYCoord(_markedEnd.y+1)-ToScrYCoord(_markedEnd.y));
 return True;
} 


//---------------------------------------------------
 
bool OXTextEdit::Goto(long line)
{
OLongPosition pos;
 if (line-1 >= _text->RowCount())
  return False;
 pos.y = line;
 pos.x = 0;
 SetVsbPosition((ToScrYCoord(line-1)+_visible.y)/_scrollVal.y);
 SetHsbPosition(0);
 SetCurrent(pos);
 return True;
}

//---------------------------------------------------

void OXTextEdit::SetCurrent(OLongPosition new_coord)
{
  delete csr_timer;
  DrawCursor(2);
  _current.y = new_coord.y;
  _current.x = new_coord.x;
  DrawCursor(1);
  csr_timer = new OTimer(this, 500);        
  SendMessage(_parent, MK_MSG(XC_VIEW,VIEW_DATACHANGE), _ID,0);

}

//---------------------------------------------------

void OXTextEdit::DrawCursor(int mode)
{
 char count = -1;
 char cursor = ' ';
 if ((_current.y >= _text->RowCount()) || (_current.x > _text->GetLineLength(_current.y)))
  return;
 if ((_current.y >= ToObjYCoord(_visible.y)) 
     && (_current.y <= ToObjYCoord(_visible.y+_canvas->GetHeight()))
     && (_current.x >= ToObjXCoord(_visible.x, _current.y)) 
     && (_current.x <= ToObjXCoord(_visible.x+_canvas->GetWidth(),_current.y)))
 {
  if (_current.y < _text->RowCount())   
   count = _text->GetChar(_current);
  if (count == -1)
   cursor =' ';
  else 
   cursor = count;
  if (mode == 2)
  {
   if ((_isMarked == 1) && (count != -1))
   {
    if (((_current.y > _markedStart.y) && (_current.y < _markedEnd.y))
        || ((_current.y == _markedStart.y) && (_current.x >= _markedStart.x)
             && (_current.y < _markedEnd.y))
        || ((_current.y == _markedEnd.y) && (_current.x <= _markedEnd.x)
             && (_current.y > _markedStart.y))
        || ((_current.y == _markedStart.y) && (_current.y == _markedEnd.y) &&
            (_current.x >= _markedStart.x) && (_current.x <= _markedEnd.x)
            && (_markedStart.x != _markedEnd.x)))
     XDrawImageString(GetDisplay(), _canvas->GetId(), _gc_marked, ToScrXCoord(_current.x,_current.y),
                       ToScrYCoord(_current.y+1) - _font->descent, &cursor, 1);
    else
     XDrawImageString(GetDisplay(), _canvas->GetId(), _gc, ToScrXCoord(_current.x,_current.y),
                       ToScrYCoord(_current.y+1) - _font->descent, &cursor, 1);
   }
   else
   {
     XDrawImageString(GetDisplay(), _canvas->GetId(), _gc, ToScrXCoord(_current.x,_current.y),
                       ToScrYCoord(_current.y+1) - _font->descent, &cursor, 1);
   }   
  }
  else 
   if (mode == 1)
     XDrawLine(GetDisplay(), _canvas->GetId(), _gc_crs1,ToScrXCoord(_current.x, _current.y),
                                  ToScrYCoord(_current.y),
                                  ToScrXCoord(_current.x, _current.y),
                                  ToScrYCoord(_current.y+1)-1);
 } 
}

//---------------------------------------------------

void OXTextEdit::AdjustPos()
{
 OLongPosition pos;
 pos.y = _current.y;
 pos.x = _current.x;

 if (pos.y < ToObjYCoord(_visible.y))
  pos.y = ToObjYCoord(_visible.y);
 else
  if (ToScrYCoord(pos.y+1) >=  _canvas->GetHeight())
   pos.y = ToObjYCoord(_visible.y + _canvas->GetHeight())-1;
 if (pos.x < ToObjXCoord(_visible.x, pos.y))
  pos.x = ToObjXCoord(_visible.x, pos.y);
 else
  if (ToScrXCoord(pos.x, pos.y) >=  _canvas->GetWidth())
   pos.x =  ToObjXCoord(_visible.x + _canvas->GetWidth(), pos.y)-1;
 if ((pos.y != _current.y) || (pos.x != _current.x))
  SetCurrent(pos); 
}

//---------------------------------------------------

int OXTextEdit::HandleTimer (OTimer *t)
{
 if (t != csr_timer)
 {
  OXTextView::HandleTimer(t);
  return True;
 }
 if (cursorstate == 1)
  cursorstate = 2;
 else
  cursorstate = 1;         
 DrawCursor(cursorstate);
 delete csr_timer;
 csr_timer = new OTimer(this, 500);
 return True;
}

//---------------------------------------------------

int OXTextEdit::HandleSelection (XSelectionEvent *event)
{
 OLongPosition start_src, end_src, pos;
 OText *newclip;
 long count, old_pos;
 Atom actual_type_return;
 int actual_format_return;
 unsigned long nitems_return, bytes_after_return;
 unsigned char *prop_return;
 char *buffer, *temp_buffer;
 XGetWindowProperty(GetDisplay(), _id, event->property, 0, LONG_MAX, False,
                AnyPropertyType, &actual_type_return, &actual_format_return,
                 &nitems_return, &bytes_after_return, &prop_return);

 if (actual_type_return != XA_STRING)
        return True;

 buffer = new char[nitems_return+1];
 buffer[nitems_return] = '\0';
 strncpy(buffer, (char*)prop_return, nitems_return);
 newclip = new OText();
 pos.y = pos.x = 0;
 count = old_pos = 0;
 while(count <= nitems_return)
 {
  if ((buffer[count] == 10) || (count == nitems_return))
  {
   temp_buffer = new char[count-old_pos+1];
   temp_buffer[count-old_pos]='\0';
   strncpy(temp_buffer, buffer+old_pos, count-old_pos);
   newclip->InsText(pos, temp_buffer);
   delete temp_buffer;
   old_pos = count+1;
   pos.y++;  
  }
  count++;
 }
delete buffer;
delete _clipboard;
delete prop_return;
_clipboard = newclip;
pos.x = pos.y = 0;
char *templine;

 start_src.y = start_src.x = 0;
   end_src.y = _clipboard->RowCount()-1;
 end_src.x = _clipboard->GetLineLength(end_src.y)-1;
 if (end_src.x < 0)
  end_src.x = 0;
 _text->InsText(_current, _clipboard, start_src, end_src);
 UnMark();
  pos.y = _current.y+_clipboard->RowCount()-1;
    pos.x = _clipboard->GetLineLength(_clipboard->RowCount()-1);    
    if (start_src.y == end_src.y)
     pos.x = pos.x + _current.x;
    SetCurrent(pos);
    if (ToScrYCoord(pos.y) >= _canvas->GetHeight())
     pos.y = ToScrYCoord(pos.y)+_visible.y-_canvas->GetHeight()/2;
    else
     pos.y = _visible.y;
    if (ToScrXCoord(pos.x, _current.y) >= _canvas->GetWidth())
     pos.x = ToScrXCoord(pos.x, _current.y) + _visible.x + _canvas->GetWidth()/2;
    else
     if ((ToScrXCoord(pos.x, _current.y) < 0) && (pos.x != 0))
    {
     if (_visible.x - _canvas->GetWidth()/2 > 0)   
      pos.x = _visible.x - _canvas->GetWidth()/2;
     else
     pos.x = 0;
    }   
    else
     pos.x = _visible.x;

   SetSBRange(HORIZONTAL);
   SetSBRange(VERTICAL);
   SetVsbPosition(pos.y/_scrollVal.y);
   SetHsbPosition(pos.x/_scrollVal.x);
}

//---------------------------------------------------

int OXTextEdit::HandleButton(XButtonEvent *event)
{
 if (event->window != _canvas->GetId())
  return True;
 OLongPosition pos;
 OXTextView::HandleButton(event);
 if ((event->button == Button1) && (event->type == ButtonPress))
 {
  pos.y = ToObjYCoord(_visible.y+event->y);
  if (pos.y >= _text->RowCount())
   pos.y = _text->RowCount()-1;
  pos.x = ToObjXCoord(_visible.x+event->x, pos.y);
  if (pos.x >= _text->GetLineLength(pos.y))
   pos.x = _text->GetLineLength(pos.y);
  if (_text->GetChar(pos) == 16)
  {
    do
     pos.x++;
    while(_text->GetChar(pos) == 16);
  }
  SetCurrent(pos); 
 }
 return True;
}

//---------------------------------------------------

int OXTextEdit::HandleMotion(XMotionEvent *event)
{
 OLongPosition pos;
 if (event->window != _canvas->GetId())
  return True;
// OXTextView::HandleMotion(event);
  if (_scrolling == -1)
  {
   pos.y = ToObjYCoord(_visible.y+event->y);
   if (pos.y >= _text->RowCount())
    pos.y = _text->RowCount()-1;
   pos.x = ToObjXCoord(_visible.x+event->x, pos.y);
   if (pos.x > _text->GetLineLength(pos.y))
    pos.x = _text->GetLineLength(pos.y);
   if (_text->GetChar(pos) == 16)
   {
    if (pos.x < _current.x)
     pos.x = _current.x;
    if (pos.x > _current.x) 
    do
      pos.x++;  
     while(_text->GetChar(pos) == 16);
   }
   event->y = ToScrYCoord(pos.y);
   event->x = ToScrXCoord(pos.x, pos.y);
   if ((pos.y != _current.y) || (pos.x != _current.x))
   {
    OXTextView::HandleMotion(event);
    SetCurrent(pos); 
   }
  }
 return True;
}

//---------------------------------------------------

int OXTextEdit::HandleKey(XKeyEvent *event)
{
 bool mark_ok=False;
 char input[2];
 int input_size = 2;
 int  charcount;
 input[0] = 0;
 KeySym keysym;
 XComposeStatus compose;
 if (event->type == KeyPress)
 {
  charcount = XLookupString(event, input, input_size, &keysym,
                           &compose); 
 AdjustPos();
   switch (keysym) {
     case XK_Shift_L:         
     case XK_Shift_R:         
     case XK_Control_L:            
     case XK_Control_R:            
     case XK_Caps_Lock:            
     case XK_Shift_Lock:           
     case XK_Meta_L:               
     case XK_Meta_R:               
     case XK_Alt_L:                
     case XK_Super_L:              
     case XK_Super_R:              
     case XK_Hyper_L:              
     case XK_Hyper_R:              
      return True;
      break;  
    }
   if (event->state & ControlMask)
   {
    switch(keysym) {
     case 0x63:
      Copy();
      break;
     case 0x76:
      Paste();
      break;
     case 0x78:
      Cut();
      break;
     default:
      break;
     }
     return True;
   }
   if ((keysym > 0x1F) && (keysym < 0xff)) 
   {
    if (_isMarked)
     Cut();
    InsChar(input[0]);
   }
   else 
   switch (keysym) {     
    case XK_F3:
      SendMessage(_parent, MK_MSG(XC_VIEW,VIEW_F3), _ID, True);
      break;
    case XK_Delete :
      if (_isMarked)
       Cut();
      break;
    case XK_Return :
      BreakLine();
      break;
     case XK_Tab :
      InsChar('\t');
      break;
     case XK_BackSpace :
      DelChar();
      break;
     case XK_Left :
      mark_ok=True;     
      PrevChar();
      break;
     case XK_Right :
      mark_ok=True;
      NextChar();
      break;
     case XK_Up :
      mark_ok=True;
      LineUp();
      break;
     case XK_Down :
      mark_ok=True;
      LineDown();
      break;
     case XK_Page_Up :
      mark_ok=True;
      ScreenUp();
      break;
     case XK_Page_Down :
      mark_ok=True;
      ScreenDown();
      break;
     case XK_Home :
      mark_ok=True;
      Home();
      break;
     case XK_End :
      mark_ok=True;
      End();
      break;
     default:
      break;
   }
   if ((event->state & ShiftMask == True) && (mark_ok))
   {    
    _isMarked = True;
    Mark(_current.x, _current.y);
    SendMessage(_parent, MK_MSG(XC_VIEW,VIEW_ISMARKED), _ID, True);
   }
   else
   {
    if (_isMarked == True)
    {
     _isMarked = False;     
     UnMark();
     SendMessage(_parent, MK_MSG(XC_VIEW,VIEW_ISMARKED), _ID, False);
    }
     _markedStart.y = _markedEnd.y = _current.y;
     _markedStart.x = _markedEnd.x = _current.x;
   }
 }
 return True;
}

//---------------------------------------------------

void OXTextEdit::InsChar(char character)
{
 char *charstring;
 OLongPosition pos;
 if (character == '\t')
 {
  pos.x = _current.x;
  pos.y = _current.y;
  _text->InsChar(pos, '\t');
  pos.x++;
  for (int i = 0; i < 7; i++)
  {
   _text->InsChar(pos,16);
   pos.x++;
   charstring = new char[9];
   charstring[8] = '\0';
   for (int j=0; j < 8;j++)
    charstring[j]=' ';
  }
 }
 else
 {
  _text->InsChar(_current, character);
  pos.x = _current.x + 1;
  pos.y = _current.y;
  charstring= new char[2];
  charstring[1] = '\0';
  charstring[0] = ' ';
 }
 SetSBRange(HORIZONTAL);
 if (ToScrXCoord(pos.x, pos.y) >= _canvas->GetWidth())
 {
  if (pos.x != _text->GetLineLength(_current.y))
   SetHsbPosition((_visible.x+_canvas->GetWidth()/2)/_scrollVal.x);
  else 
   SetHsbPosition(_visible.x/_scrollVal.x+strlen(charstring)); 
  if (_hsb == NULL)
   XDrawImageString(GetDisplay(), _canvas->GetId(), _gc, ToScrXCoord(_current.x, _current.y),
                    ToScrYCoord(_current.y+1) - _font->descent, charstring, strlen(charstring));
     
 }
 else
 {

  XCopyArea(GetDisplay(), _canvas->GetId(), _canvas->GetId(), _gc, ToScrXCoord(_current.x, _current.y), 
             ToScrYCoord(_current.y),_canvas->GetWidth(), ToScrYCoord(_current.y+1)-ToScrYCoord(_current.y), 
             ToScrXCoord(pos.x, _current.y),ToScrYCoord(_current.y)); 
  XDrawImageString(GetDisplay(), _canvas->GetId(), _gc, ToScrXCoord(_current.x, _current.y),
                    ToScrYCoord(_current.y+1) - _font->descent, charstring, strlen(charstring));     
 }
 delete charstring;
 SetCurrent(pos);  
}

//---------------------------------------------------

void OXTextEdit::DelChar()
{
 char *buffer;
 OLongPosition pos, pos2;
 long len;
 pos.y = _current.y;
 pos.x = _current.x;

 if (_current.x > 0)
 {
  pos.x--;
  if (_text->GetChar(pos) == 16)
  {
   pos.x = _current.x;
   for (unsigned long t=0; t < 8; t++)
   {
    _text->DelChar(pos);
    pos.x--;
   }
   DrawRegion(0, ToScrYCoord(pos.y), _canvas->GetWidth(), ToScrYCoord(pos.y+2)-ToScrYCoord(pos.y));
  }
  else
  {
   pos.x = _current.x;
   _text->DelChar(_current);
   pos.x = _current.x - 1;
  }
  if (ToScrXCoord(_current.x-1, _current.y) < 0)
   SetHsbPosition((_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);
  SetSBRange(HORIZONTAL);
  DrawRegion(0, ToScrYCoord(pos.y), _canvas->GetWidth(), ToScrYCoord(pos.y+2)-ToScrYCoord(pos.y)); 
 }
 else
 {
  if (_current.y > 0)
  {
   len = _text->GetLineLength(_current.y);
   if (len > 0)
   {
    buffer = _text->GetLine(_current, len);
    pos.y--;
    pos.x = _text->GetLineLength(_current.y-1);
    _text->InsText(pos, buffer);
    pos.y++;
    delete buffer;
   }
   else
    pos.x = _text->GetLineLength(_current.y -1);
   pos2.y  = ToScrYCoord(_current.y+1);
   pos.y = _current.y - 1;
   _text->DelLine(_current.y);
   len = _text->GetLineLength(_current.y-1);
   if (ToScrXCoord(pos.x, _current.y-1) >= _canvas->GetWidth())
    SetHsbPosition((ToScrXCoord(pos.x, pos.y)+_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);

   XCopyArea(GetDisplay(), _canvas->GetId(), _canvas->GetId(), _gc, 0, pos2.y,
                _w, _canvas->GetHeight() - ToScrYCoord(_current.y), 0, ToScrYCoord(_current.y));
   if (ToScrYCoord(pos.y) < 0)
    SetVsbPosition(_visible.y/_scrollVal.y-1);
   DrawRegion(0, ToScrYCoord(pos.y), _canvas->GetWidth(), ToScrYCoord(pos.y+1) - ToScrYCoord(pos.y));
   SetSBRange(VERTICAL);
   SetSBRange(HORIZONTAL);
  }
 }
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::BreakLine()
{
 OLongPosition pos;
 _text->BreakLine(_current);
 if (ToScrYCoord(_current.y+2) <= _canvas->GetHeight())
 {
  XCopyArea(GetDisplay(), _canvas->GetId(), _canvas->GetId(), _gc, 0,
            ToScrYCoord(_current.y+1),_canvas->GetWidth(),   
            _canvas->GetHeight()-(ToScrYCoord(_current.y+2)- ToScrYCoord(_current.y)), 
            0,ToScrYCoord(_current.y+2)); 
  DrawRegion(0, ToScrYCoord(_current.y),_canvas->GetWidth(), 
                ToScrYCoord(_current.y+2) - ToScrYCoord(_current.y));

  if (_visible.x != 0)
   SetHsbPosition(0);
 SetSBRange(HORIZONTAL);
 SetSBRange(VERTICAL);
 }
 else
 {
 SetSBRange(HORIZONTAL);
 SetSBRange(VERTICAL);
  SetVsbPosition(_visible.y/_scrollVal.y +1);
  DrawRegion(0, ToScrYCoord(_current.y),
                _canvas->GetWidth(), ToScrYCoord(_current.y+1)- ToScrYCoord(_current.y));
 }
 pos.y = _current.y+1;
 pos.x = 0;
 SetCurrent(pos);
}

 //--------------------------------------   

void OXTextEdit::TabKey()
{
/* int i;
 for (i = 0; i < 8; i++)
  InsChar('\t');*/
}

//--------------------------------------

void OXTextEdit::PrevChar()
{
 OLongPosition pos;
 long len;
 pos.y = _current.y;
 pos.x = _current.x;
  if (_current.x > 0)
  {
   pos.x--;
   if (_text->GetChar(pos) == 16)
    pos.x = pos.x - 7;
   if (ToScrXCoord(pos.x, pos.y) < 0)
    if (_visible.x-(_canvas->GetWidth()/2) >= 0)
     SetHsbPosition((_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);
    else
     SetHsbPosition(0);
  }
  else
  {
   if (_current.y > 0)
   {
    pos.y = _current.y - 1;
    len = _text->GetLineLength(pos.y);
    if (ToScrYCoord(_current.y) <= 0)
     SetVsbPosition(_visible.y/_scrollVal.y-1);
    if (ToScrXCoord(len, pos.y) >= _canvas->GetWidth())
     SetHsbPosition((ToScrXCoord(len, pos.y)+_visible.x - _canvas->GetWidth()/2)/_scrollVal.x);
    pos.x = len;
   }
  }
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::NextChar()
{
 OLongPosition pos;
 long len = _text->GetLineLength(_current.y);
 pos.y = _current.y;
  if (_current.x < len)
  {

   if (_text->GetChar(_current) == '\t')
    pos.x = pos.x +8;
   else
    pos.x = _current.x +1;
   
   if (ToScrXCoord(pos.x, pos.y) >= _canvas->GetWidth())
   {
    SetHsbPosition(_visible.x/_scrollVal.x+(_canvas->GetWidth()/2)/_scrollVal.x);
   }
  }
  else
  {
   if (_current.y < _text->RowCount()-1)
   {
    pos.y = _current.y + 1;
    if (ToScrYCoord(pos.y+1) >=  _canvas->GetHeight())
     SetVsbPosition(_visible.y/_scrollVal.y+1);
    SetHsbPosition(0);
    pos.x = 0;
   }
  } 
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::LineUp()
{
 OLongPosition pos;
 long len;
 if (_current.y > 0)
 {
   pos.y = _current.y - 1;
  if (ToScrYCoord(_current.y) <= 0)
  {
   SetVsbPosition(_visible.y/_scrollVal.y-1);
  }
  len = _text->GetLineLength(_current.y-1);
  if (_current.x > len)
  {
   if (ToScrXCoord(len, pos.y) <= 0)
   {
    if (ToScrXCoord(len, pos.y) < 0)
    {
     SetHsbPosition(ToScrXCoord(len, pos.y)+(_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);
    }
    else 
    {
     SetHsbPosition(0);
    }
   }
   pos.x = len;
  }
  else
   pos.x = ToObjXCoord(ToScrXCoord(_current.x, _current.y)+_visible.x, pos.y);
   while(_text->GetChar(pos) == 16)
     pos.x++;
  SetCurrent(pos);
 }
}

//--------------------------------------

void OXTextEdit::LineDown()
{
 OLongPosition pos;
 long len;
 if (_current.y < _text->RowCount()-1)
 {
  len = _text->GetLineLength(_current.y+1);
  pos.y = _current.y +1;
  if (ToScrYCoord(pos.y+1) > _canvas->GetHeight())
   SetVsbPosition(_visible.y/_scrollVal.y+1);
  if (_current.x > len)
  {
   if (ToScrXCoord(len, pos.y) <= 0)
   {
    if (ToScrXCoord(len, pos.y) < 0)
     SetHsbPosition((ToScrXCoord(len, pos.y)+_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);
    else 
     SetHsbPosition(0);
   }
   pos.x = len;
  }   
  else
   pos.x = ToObjXCoord(ToScrXCoord(_current.x, _current.y)+_visible.x, pos.y);
   while(_text->GetChar(pos) == 16)
     pos.x++;
  SetCurrent(pos);
 }
}

//--------------------------------------

void OXTextEdit::ScreenUp() 
{
 OLongPosition pos;
 pos.x = _current.x;
 pos.y = _current.y - (ToObjYCoord(_canvas->GetHeight())-ToObjYCoord(0))-1;
 if (_visible.y - _canvas->GetHeight() >= 0)  // +1
 {
  SetVsbPosition((_visible.y - _canvas->GetHeight())/_scrollVal.y);
 }
 else
 {
  pos.y = 0;
  SetVsbPosition(0);
 }
 while(_text->GetChar(pos) == 16)
  pos.x++;
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::ScreenDown() 
{
 OLongPosition pos;
 pos.x = _current.x;
 pos.y = _current.y + (ToObjYCoord(_canvas->GetHeight()) - ToObjYCoord(0));
 long count = _text->RowCount()-1;
 if (_canvas->GetHeight() < ToScrYCoord(count))
 {
  SetVsbPosition((_visible.y+_canvas->GetHeight())/_scrollVal.y); 
 }
 else
  pos.y = count; 
 while(_text->GetChar(pos) == 16)
  pos.x++;
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::Home()
{
 OLongPosition pos;
 pos.y = _current.y;
 pos.x = 0;
 SetHsbPosition(0);
 SetCurrent(pos);
}

//--------------------------------------

void OXTextEdit::End()
{
 OLongPosition pos;
 pos.y = _current.y;
 pos.x = _text->GetLineLength(pos.y);
 if (ToScrXCoord(pos.x, pos.y) >= _canvas->GetWidth())
  SetHsbPosition((ToScrXCoord(pos.x, pos.y)+_visible.x-_canvas->GetWidth()/2)/_scrollVal.x);
 SetCurrent(pos);
}



