

/*

04:59 17/02/2014
14:31 31/10/2014
Charles E V Pegge

DEPENDENCIES
============

Text:
ParseUtil.inc

Opengl
OpenglUtil.inc

mouse:
mposx,mposy,sposx,sposy

keyboard:
keyt,keyc

picking mode:
picklevel

clipping:
SetClipPlanes()
DisClipPlanes()

Font/Typeface:

Boxing:
GetWordArea()
PutBoxArea()

Borders:
SetBorder()

Modality:
ViewMode =5


Invoking:
Controls.inc

exclu 'buttonup / openglview.inc

*/

  % TexColor ColorI 0xff909080 'standard

  'dark palette
  '
  %    TextCol    0xd0909080    'Main text color
  %    BackCol    0xd0601010    'Main background color
  %    HighCol    0xa00000a0    'Highlighting background color
  %    MarkFcol   0xd020e0e0    'Marked word forground color
  %    MarkBcol   0xd0a0a000    'Marked word background color
  %    RemCol     0xd02040e0    'Remark/comment text color
  %    QuoteCol   0xd000e0e0    'Quoted text color
  %    KeyCol     0xd0d0e0e0    'Keyword/Syntax color
  %    CaretCol   0xd040e0e0    'Caret color
  %    LineNoCol  0xd0008000    'Line number color
  %    BorderCol  0xe070e0e0    'Border color
  %    BarCol     0x50000080    'Bar color



/*
  'light palette
  '
  %    TextCol    0xf0302030    'Main text color
  %    BackCol    0xd0ffffff    'Main background color
  %    HighCol    0xa0ffff40    'Highlighting background color
  %    MarkFcol   0xf0202090    'Marked word forground color
  %    MarkBcol   0xc0a0ffff    'Marked word background color
  %    RemCol     0xf0102080    'Remark/comment text color
  %    QuoteCol   0xf0002020    'Quoted text color
  %    KeyCol     0xf0001010    'Keyword/Syntax color
  %    CaretCol   0xf0102010    'Caret color
  %    LineNoCol  0xf0007000    'Line number color
  %    BorderCol  0xf0202070    'Border color
  %    BarCol     0x400000a0    'Bar color
*/



type rectf
  single x,y,w,h
end type
'
'
'==================
Class EditBoxObject
'==================

  'TEXT LOCATION (FILE .. CHARACTER)
  '---------------------------------
  sys     et           'number of lines

  sys     SelLine      'picker
  sys     SelWord      'picker
  sys     SelChar      'picker

  sys     SttLinePos   'start text line position in file (blocks)
  sys     SttCharPos   'start character position in text line (blocks)
  sys     CurLinePos   'current text line position in file 1..end
  sys     CurWordPos   'current selected word position in text line
  sys     CurCharPos   'current character position in text line (caret to the left of this char)
  bstring CurWord      'current selected word (highlighted wherever it appears on screen)
  bstring TextName     'name of text (usually the filename or full pathname)


  'KEYWORDS/SYNTAX
  '---------------

  bstring keywords    'list of keywords (lowercase separated by white space)

  'ABILITIES
  '---------

  sys    BlockSelAble 'Enable Block selection of text
  sys    EditAble     'Enable Editing



  'OBJECT
  '------

  sys    ido   'object identity number
  sys    ndis  'display refresh flag (new display)
  sys    lino  'flage to display line numbers
  sys    ofs   'line offset for first line on display
  sys    oofs  'line offset for first line on display (on keypress)
  sys    q     'how many lines to display
  sys    oms   'object mode selection flag (moving scaling highlighting)


  'VIEWPORT (PIXEL) METRICS
  '------------------------

  sys    ewh   'edit window height
  sys    eww   'edit window width
  sys    ewx1  'coord
  sys    ewx2  'coord
  sys    ewy1  'coord
  sys    ewy2  'coord


  'SPATIAL METRICS
  '---------------

  single d     'size of character (font)
  single ypd   'base padding
  single vpr   'viewport y/x ratio
  single spd   'micro-scrolling speed factor
  single yscrl 'scroller line displacement (vertical)
  single xscrl 'scroller line displacement (horizontal)
  single scrc  'caret offset used for horizontal scrolling
  single xd    'displacement of the control from the eyeview centre
  single yd    'displacement of the object from the eyeview centre
  single sclx  'x scale of the object
  single scly  'y scale of the object
  single od    'prior font size
  single oxd   'prior value of xd before a move (mouse drag)
  single oyd   'prior value of yd before a move (mouse drag)
  single osclx 'prior value of sclx before rescaling (mouse drag/pull)
  single oscly 'prior value of scly before rescaling (mouse drag/pull)
  sys    onl   'prior value of q line count before rescaling (mouse drag/pull)


  'RENDERING
  '---------

  sys    a,c,e,f   'scratch
  sys    i,j,n,p   'scratch
  sys    gn        'word position index (on text line)
  sys    mpx,mpy   'mouse position inside control
  sys    dpx,dpy   'mouse drag distance
  sys    qu        'quote flag (rendering text)
  '
  single xp,yp     'coordinates
  single scv       'y scrolling step size
  single gfx,gfy   'word area
  single xtxt,ytxt 'text coordintes
  single rto       'scale conversion factor viewport/text coor
  single b,v,vv    'scratch
  single lmx       'text right margin, display limit

  bstring tx0,tx1,tx2
  TextArray * txt


  'PICK ZONES
  '----------

  rectf  txc[0x40]   'word metrics x,y,w,h
  sys    txd[0x40]   'word/char position on line
  bstring txa[0x40]  'words on line

  'MOVING AND RESCALING FROM OUTSIDE
  '---------------------------------

  single pxd,pyd,pxc,pyc



  'COLORS
  ' Alpha Blue Green Red 
  '0xAABBGGRR
  '------
  
  method constructor()
  ====================
  '
  end method




  method destructor()
  ===================
  for i=1 to 40 :frees txa[i] : next
  frees curword
  frees textname
  frees keywords
  frees tx0
  frees tx1
  frees tx2
  end method


  method PickChar()
  =================
  '
  select picklevel
  '
  case 1 'LINE IDENTIFICATION
    '
    'use box in place of text
    '
    CurCharPos=1
    CurWordPos=0
    CurLinePos=0
    glLoadname j
    PutBoxArea b,yp,vpr*2*scly,d 'full width to pick empty lines
    '
  case 2 'WORD IDENTIFICATION
    '
    'only interested in the identified line
    '
    if SelLine=j
      '
      CurLinePos=j
      CurCharPos=txt.length(j)+1 'default
      c=1 : e=len tx0
      do
        if c>e then exit do
        if gn=63 then exit do
        gn+=1 : glLoadname gn
        txd[gn]=c 'record position on line
        a=c
        tx1=getword tx0, c
        tx1=mid tx0,a,c-a 'including leading space
        GetWordarea tx1, gfx, gfy 'including leading space
        gfx*=d
        PutBoxArea b,yp,gfx,d
        '
        'record words on line and locations for syntax handling
        '
        txa[gn]=tx1          'store word
        txc[gn]<=b,yp,gfx,d 'store area box
        b+=gfx
        '
      end do
      '
    end if
    '
  case 3 'CHAR IDENTIFICATION
    '
    if SelLine=j
      tx1=txa[SelWord] : a=SelWord*4
      b=txc[SelWord].x 'word offset
      c=1 : e=len tx1
      if e>63 then e=63
      do
        if c>e then exit do
        if gn>=126 then exit do
        tx2=mid tx1,c,1
        GetWordarea tx2, gfx, gfy
        gfx*=d*.5 'half character
        gn+=1 : glLoadname gn
        PutBoxArea b,yp,gfx,d    'left half of char
        gn+=1 : glLoadname gn
        b+=gfx
        PutBoxArea b,yp,gfx,d 'right half of char
        b+=gfx : c+=1
      end do
      if ldblclk=2 then CurWord=ltrim lcase tx1
      CurWordPos=txd[SelWord]
    end if
  end select
  end method


  method inrange(sys a,b,c) as sys
  ======================
  if (a=b)or(b=c)or((a>b)and(b>c))or((a<b)and(b<c)) then return 1
  end method


  method RenderMainText()
  ======================
  if len tx0
    string wd,wl
    sys k=1,i=1,n
    sys aa,bw
    b=xtxt
    n=CurLinePos
    if CurLinepos>SttLinePos
      n-=1
    else
      n+=1
    end if
    do
      'BLOCK HIGHLIGHTING
      if BlockSelAble
      if sttlinepos>0
      if sttlinepos<>curlinepos 'or sttcharpos<>curcharpos
        if inrange(sttlinepos,j,n)
          wd=tx0
          GetWordArea wd,gfx,gfy 'spaces, tabs
          ColorI HighCol
          PutBoxArea b,yp,gfx*d,d
          ColorI TextCol
          RenderText wd,b,yp,d
          b+=(gfx*d)             'skip spacers
          exit do
        end if
      end if
      end if
      end if
      '
      'asnormal:
      '
      skiplspace tx0,i
      aa=asc tx0,i
      'NO MORE WORDS ON LINE
      if aa=0 then
        exit do
      end if
      cp=b
      'SPACES AND TABS
      if i>k then
        wd=mid tx0,k,i-k
        GetWordArea wd,gfx,gfy 'spaces, tabs
        b+=(gfx*d)             'skip spacers
      end if
      bw=i
      wd=getword tx0,i
      if asc(wd)=0 then
        exit do
      end if
      wl=lcase wd
      aa=asc wd
      GetWordArea(wd,gfx,gfy)
      k=i
      'SYNTAX HIGHLIGHTING
      if qu
        ColorI QuoteCol
        if aa=qu
          wd=chr(aa) 'process end quote mark only
          i=bw+1
          GetWordArea(wd,gfx,gfy)
          qu=0
        end if
      elseif instr " ; ' ",wd
        ColorI RemCol
        wd=mid(tx0,bw) 'rest of line
        GetWordArea(wd,gfx,gfy)
        i=1+len tx0 'end line
      elseif instrword CurWord,wl
        'Highlight current word
        Colori MarkBcol
        PutBoxArea b,yp,gfx*d,d
        ColorI MarkFcol
      elseif instrword keywords,wl
        ColorI KeyCol
      elseif aa=34
        ColorI QuoteCol
        if aa<>asc wd,-1
          qu=aa 'quote continued on next line
        end if
      elseif aa=96
        ColorI QuoteCol
        if aa<>asc wd,-1
          qu=aa 'quote continued on next line
        end if
      else
        ColorI TextCol
      end if
      RenderText wd,b,yp,d
      b+=(gfx*d)
    end do
  end if
  end method


  method ShowCaret()
  ==================
  ytxt=yp
  tx0=txt.line(CurLinePos)
  if CurCharPos=0 then CurCharPos=1+len tx0
  tx0=left tx0,CurCharPos-1
  GetWordArea tx0,gfx,gfy
  b+=(gfx*d)
  ColorI CaretCol
  PutBoxArea b,yp, d*.125, d 'caret as rectangle
  end method


  method SetLineNumber()
  ======================
  b+=d
  if lino
    tx1=str(j)+"  "
  else
    tx1=""
  end if
  GetWordArea tx1, gfx,gfy
  ColorI LineNoCol
  if picklevel=0 then RenderText tx1,b,yp,d
  b+=(gfx*d)
  end method

  method KeyAction()
  ==================
  '
    if keyc>0 and keyc<27 and BlockSelAble<>0
      select keyc
      case 8 to 13 : jmp fwd nctrl                                         'exclude tab, cr etc
      case 01 : SttLinePos=1 : CurLinePos=1+txt.LastLine                   'Ctrl A
      case 03 : buftxt=txt.CopyLines(SttLinePos,CurlinePos)                'Ctrl C
      case 22 : txt.PasteLines(CurLinePos,buftxt) : SttLinePos=0           'Ctrl V
      case 24 : buftxt=txt.CutLines(SttLinePos,CurlinePos) : SttLinePos=0  'Ctrl X
      end select
      a=CurCharPos
      jmp fwd nKeySel
    end if
    '
    nctrl:
    '
    ofs=oofs
    c=CurLinePos
    a=txt.length(c)+1
    e=GetAsyncKeyState(0x11) and 0x8001 'Check for Ctrl-key
    if e
      if keyt=34 then 'CTRL-PGDOWN
        CurLinePos=et
        ofs=et-q*.5
        if ofs<0 then ofs=0 
      elseif keyt=33 then 'CTRL-PGUP
        ofs=0 : CurLinePos=1
      end if
      jmp fwd nKeySel
    end if
    '
    sys nl=0
    select keyt
    case 38  : CurLinePos-=1     'ARROW UP
    case 40  : CurLinePos+=1     'ARROW DOWN
    case 37  : CurCharPos-=1     'ARROW LEFT
    case 39  : CurCharPos+=1     'ARROW RIGHT
    case 36  : CurCharPos=1      'HOME
    case 35  : CurCharPos=a      'END
    case 34  : CurLinePos+=q-2   'PG DOWN
    case 33  : CurLinePos-=(q-2) 'PG UP
    case 46  : keyc=1025         'DELETE
    '
    case 114 'F3
      if len(Curword)
        e=CurLinePos
        f=CurCharPos
        txt.locate CurWord, e, f
        if e
          CurlinePos=e : CurCharPos=f+len CurWord
          ofs=e-10
          if ofs<1 then ofs=0
          ndis=1
          SttLinePos=nl : keyt=0 : oofs=ofs ': acte=1
          'jmp fwd naction
        end if
      end if
    case else
      nl=SttLinePos
    end select
    SttLinePos=nl
    '
    'Characters to insert (or delete)
    '--------------------------------
    '
    if EditAble
    if keyc
      '
      tx0=txt.line(CurLinePos)
      '
      if keyc=1025 then  'DELETE
        if CurCharPos>txt.length(CurLinePos)
          tx1=txt.line(CurLinePos)+txt.line(CurLinePos+1)
          txt.delete(CurLinePos+1)
          txt.line(CurLinePos)=tx1
          jmp fwd nkeysel
        else
          CurCharPos+=1
          keyc=8
        end if
      end if
      '
      if keyc=8 then 'BACKSPACE DELETION
        '
        if CurCharPos=1
          if CurLinePos>1
            CurLinePos-=1
            CurCharPos=txt.length(CurLinePos)+1
            tx2=txt.line(CurLinePos)+txt.line(CurLinePos+1)
            txt.delete(CurLinePos+1)
            txt.line(CurLinePos)=tx2
          end if
          a=CurCharPos
        else 'if CurCharPos>1
          CurCharPos-=1
          txt.line(CurLinePos)=left(tx0,CurCharPos-1)+mid(tx0,CurCharPos+1)
        end if
        SttLinePos=CurLinePos
        '
        '
      elseif keyc=13 then 'ENTER
        '
        tx1=txt.line(CurLinePos)
        txt.line(CurLinePos)=left tx1,CurCharPos-1
        CurLinePos+=1
        tx2=mid tx1,CurCharPos
        txt.insert(CurLinePos)=tx2
        CurCharPos=1
        SttLinePos=CurLinePos
        '
      else 'CHAR INSERT
        '
        if txt.length(CurLinePos)=0
          tx2=chr keyc
        else
          tx2=left(tx0,CurCharPos-1)+chr(keyc)+mid(tx0,CurCharPos)
        end if
        '
        txt.line(CurLinePos)=tx2
        '
        CurCharPos+=1 : a+=1
        '
      end if
    end if
    end if 'EditAble
    '
    nkeySel:
    '=======
    '
    keyc=0 'clear char
    keyt=0 'clear keydown transient
    '
    'limit checks
    '-----------
    '
    et=txt.LastLine
    '
    if CurCharPos<1
      if CurLinePos>1
        CurLinePos-=1
        CurCharPos=txt.length(CurLinePos)+1
      else
        CurCharPos=1
      end if
    elseif CurCharPos>a
      if CurLinePos<et
        CurCharPos=1
        CurLinePos+=1
      else
        CurCharPos=a
      end if
    end if
    '
    if CurLinePos>et then CurLinePos=et 'could be 0
    if CurLinePos<1 then CurLinePos=1   'never less than 1
    '
    '
    'need screen buffer refresh for whole line scrolling?
    '----------------------------------------------------
    '
    e=0 : a=CurLinePos-c
    '
    if a<0
      if curlinepos<ofs+4 then e=-1
    elseif a
      if curlinepos>ofs+q-2 then e=1
    end if
    '
    if e<0
      ofs+=a : ndis=1 'GO UP
    elseif e>0 then
      ofs+=a : ndis=1 'GO DOWN
      if (ofs+a+q-5)>et then ofs=et-q+5
      if ofs<0 then ofs=0
    end if
    '
    oofs=ofs
    '
  '
  end method 'KeyAction


  method action()
  ===============
  '
  '
  'transient variables
  '-------------------
  '
  v=0    'line y offset
  gn=0   'name counter
  '
  'initial values
  '-------------
  '
  if q=0 then this.set 1,0,0,1,1,.02,0
  '
  'adjust params
  '-------------
  '
  if ndis=0
    if isnewview then ndis=2
  end if
  '
  if ndis 'NEW DISPLAY
    '
    et=txt.LastLine
                           'view projection ratio vpr=0.414
    rto=viewport[4]*.5/vpr 'factor gl coords to box x pixels
    b=1/aspect 'y/x ratio  'aspect is window wwidth/wheight
    '
    'box metrics in pixels
    '
    ewx1=viewport[3]*(1-sclx*b)*.5+viewport[1]+xd*rto 'left boundary
    ewy1=viewport[4]*(1-scly)*.5+viewport[2]+yd*rto   'bottom boundary
    eww=viewport[3]*sclx*b                            'width of box
    ewh= viewport[4]*scly                             'height
    ewx2=ewx1+eww                                     'right boundary
    ewy2=ewy1+ewh                                     'top boundary
    '
    if ofs<0 then ofs=0
    if oofs<0 then oofs=0
    if ndis<2 then yscrl=0
    ndis=0
    '
  end if
  '
  mpx=mposx-ewx1 'mouse x position within control (left)
  mpy=mposy-ewy1 'mouse y position within control (bottom)
  '
  if picklevel=1 'bleft or bright
    if (mpx>0)and(mpx<eww)
      if (mpy>0)and(mpy<ewh)
        if exclu=0
          if viewmode=5
            focus=ido : exclu=ido 'claim focus
          end if
        end if
      end if
    end if
    if viewmode<>5 'non edit:
      if focus=ido
        focus=0 : exclu=0
      end if
    end if
  end if
  '
  'background
  '==========
  '
  if picklevel=0
    glpushmatrix
    gltranslatef xd,yd,0
    glscalef sclx,scly,1
    SetClipPlanes vpr
    ColorI BackCol
    SetBackGround 2,2,-1.0
    glpopmatrix
  end if
  '
  '
  'PROCESS TEXT LINES
  '==================
  '
  lmx=0 : b=0 : qu=0
  v=q*d 'above top line
  e=txt.lastline()-ofs
  if q<e then e=q
  '
  for i=1 to e
    v-=d
    b=v+yscrl
    j=i+ofs 'data ref
    if b<-d or b>=1 then jmp fwd ndispl
    tx0=txt.line(j)
    '
    xp=xd-vpr*sclx       'left side of box
    yp=yd+b+ypd-vpr*scly 'bottom of box
    '
    b=xp+xscrl 'position with negative  x scrolling displacement
    SetLineNumber()
    xtxt=b
    '
    if picklevel
      if focus=ido
        if mpx>.1*eww
          PickChar()
        end if
        goto ndispl 'no further rendering required
      end if
    end if
    '
    qu=0
    RenderMainText()
    vv=b-xscrl
    if lmx<vv then lmx=vv
    if CurLinePos=0 then CurLinePos=1
    if j=CurLinePos
      b=xtxt
      ShowCaret()
      oofs=ofs
      scrc=b
    end if
    '
    ndispl:
    '
  next
  '
  '
  if picklevel
    glLoadName 0 : exit method
  end if
  '
  DisClipPlanes()
  glpushmatrix
  gltranslatef xd,yd,0
  glscalef sclx,scly,1
  ColorI BorderCol
  SetBorder vpr,vpr,-1
  ColorI BarCol
  DrawBar   vpr,vpr,-1
  glpopmatrix
  '
  if focus<>ido
    oms=0 : exit method
  end if
  '
  '
  'SCALING MOVING HIGHLIGHTING
  '============================
  '
  if mpx<d
    oms=0 : jmp fwd nscale
  end if
  if bleft+bright=0
    oms=0 : jmp fwd nscale
  end if

  acte=bleft+bmid+bright+keyd

  if oms=0
    osclx=sclx : oscly=scly : onl=q : oxd=xd : oyd=yd : od=d
  else
    goto dynscale
  end if
  '
  '
  if bleft 'left mouse button down
    '
    if mpx>.1*eww
      if BlockSelAble then oms=9 'default (for text block)
    end if
    '
    if mpy>.9*ewh
      if mpx>.9*eww
        oms=5 'X Y SIZING TOP RIGHT
      elseif mpx>0.3*eww
        oms=4 'MOVE
      end if
    elseif mpy<.1*ewh
      if mpx>.9*eww
        oms=1 'X Y SIZING BOTTOM RIGHT
      elseif mpx>.3*eww
        oms=2 'Y SIZING
      end if
    end if
    jmp fwd dynscale
    '
  end if
  '
  if bright
    if mpy<ewh
      if mpx>.1*eww then oms=3 'SCALE
    end if
  end if
  '
  '
  dynScale: 'DYNAMIC SCALING AND MOVING WITH MOUSE
  =========
  '
  if oms
    '
    dpx=mposx-sposx
    dpy=mposy-sposy
    single a
    '
    select oms
    '
    case 1 'BOTTOM RIGHT RESIZE
    '
    sclx=osclx+dpx/(rto*vpr*2) 'X SCALING
    if sclx<.02 then sclx=.02
    xd=oxd+vpr*(sclx-osclx) 'anchor adjustment
    '
    scly=oscly-dpy/(rto*vpr*2) 'Y SCALING
    if scly<.02 then scly=.02
    yd=oyd+vpr*(oscly-scly) 'anchor adjustment
    '
    q=scly*vpr*2/d 'onl*scly/oscly 'line count
    a=scly*vpr*2
    q=a/d   'line count (int truncation)
    ypd=a-q*d 'baseline padding
    ndis=2
    jmp fwd naction
    '
    case 2 'BOTTOM RESIZE
    '
    scly=oscly-dpy/(rto*vpr*2) '
    if scly<.02 then scly=.02
    yd=oyd+vpr*(oscly-scly)
    a=scly*vpr*2
    q=a/d   'line count
    ypd=a-q*d 'base line padding
    ndis=2
    jmp fwd naction
    '
    case 3 'SCALE
    '
    d=od+dpy*.0001
    if d<.004 then d=.004
    a=scly*vpr*2
    q=a/d   'line count
    ypd=a-q*d 'base line padding
    ndis=1
    jmp fwd naction
    '
    case 4 'MOVE
    '
    xd=oxd+dpx/rto 'MOVE X
    yd=oyd+dpy/rto 'MOVE Y
    ndis=2
    jmp fwd naction
    '
    case 5 'TOP RIGHT RESIZE
    '
    sclx=osclx+dpx/(rto*vpr*2) 'X SCALING
    if sclx<.02 then sclx=.02
    '
    scly=oscly+dpy/(rto*vpr*2) 'Y SCALING
    if scly<.02 then scly=.02
    '
    q=scly*vpr*2/d 'onl*scly/oscly 'line count
    a=scly*vpr*2
    q=a/d   'line count (int truncation)
    ypd=a-q*d 'baseline padding
    xd=oxd+dpx*.5/rto 'MOVE X
    yd=oyd+dpy*.5/rto 'MOVE Y
    ndis=2
    jmp fwd naction
    '
    end select
  end if
  '
  '
  nscale:
  '------
  '
  'KEYBOARD
  '
  if keyt then
    'if viewmode=5 'EDIT MODE
      KeyAction()
    'end if
  end if
  '
  '
  'AUTOSCROLL ZONE CONFINEMENT
  '---------------------------
  '
  if curcharpos<5 then 
    if xscrl<0 then xscrl+=.01
    if xscrl>0 then xscrl=0
  end if
  '
  if xscrl<0      then jmp fwd nvscroll
  if mpx>0.1*eww  then jmp fwd nvscroll
 'if mpx<0        then jmp fwd nhscroll
 'if mpx>eww      then jmp fwd nhscroll
  if bleft=0      then jmp fwd nvscroll
  '
  'VERTICAL AUTOSCROLLING
  '
  scv=d*spd*(sposy-mposy)*10*agr/ewh
  yscrl+=scv
  ndis=2
  '
  if mposy<sposy
    if yscrl>=d
      n=yscrl/d 'quantise
      a=n+ofs+q-1
      if a>et
        yscrl-=scv
      else
        ofs+=n
        yscrl-=n*d
      end if
    end if
   else 'SCROLL UP
    if ofs<=0
      yscrl-=scv
    else
      if yscrl<0
        n=-yscrl/d
        ofs-=n
        if ofs<0 then n-=ofs : ofs=0
        yscrl+=n*d
      end if
    end if
  end if
  '
  '
  naction:
  nvscroll:
  '
  'HORIZONTAL AUTOSCROLLING RIGHT AND LEFT
  '
  '
  a=(scrc+vpr)*rto-ewx1 'convert caret position to box x pixel position
  '
  if a>eww*0.8 
    xscrl-=spd*(a-eww*.8)*.001  'scroll right
  elseif a<eww*0.2
    xscrl-=spd*(a-eww*.2)*.001 'scroll left
  end if
  '
  'limits
  '
  if xscrl>0
    xscrl=0    'left (margin) scrolling limit
  elseif xscrl<=-lmx
    xscrl=-lmx 'right scrolling limit
  end if
  '
  'gliding scroll continuing action
  '
  'nhscroll:
  '
  typeof(scrscrl) pxscrl
  if pxscrl<>xscrl
    acte=1
    pxscrl=xscrl
  end if
  'can also test for other continuing actions
  '
end method 'action


method render()
'===============
  '
  SetProjection(0) 'standard 3d
  '
  glEnable GL_LINE_SMOOTH
  glDisable GL_LIGHTING
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 'Enable Alpha Blending
  glEnable(GL_BLEND)                                'Enable Blending
  glAlphaFunc(GL_GREATER,0.1)                       'Set Alpha Testing
  glEnable(GL_ALPHA_TEST)                           'Enable Alpha Testing
  Lighting() 'also disables wireframe mode
  '
  action
  '
  glDisable(GL_ALPHA_TEST)
  glDisable GL_BLEND
  glDisable GL_ALPHA_TEST
  '
end method


method zone()
'============
  SelLine=0 : SelWord=0 : SelChar=0
  if bleft
    picklevel=1
    PickPrep : action : PickResult
    if SelObject
      SelLine=SelObject : picklevel=2
      PickPrep : action : PickResult
      if SelObject
        SelWord=SelObject : picklevel=3
        PickPrep : action : PickResult
        if SelObject
          Selchar=SelObject>>1
          'falling left or right of the selected char
          CurCharPos=CurWordPos+SelChar
        end if
      end if
      if oms=9
        SttLinePos=CurLinePos
        SttCharPos=CurCharPos
        oms=10 'anchor for block selection
      end if
    end if
  end if
  picklevel=0
end method


method LineNumber() as sys
'=========================
  return CurLinePos
end method


method GetLine(sys n) as string
'==============================
  if n=0 then n=CurLinePos
  if n
    return txt.line[n]
  end if
end method


method PutLine(string s, sys n)
'==============================
  if n=0 then n=CurLinePos
  if n
    txt.line(n)=s
  end if
end method


method Load(string s)
'====================
  if s
    if TextName<>s
      txt.load s
      CurLinePos=1
      CurCharPos=1
      SttLinePos=0
      xscrl=0
      yscrl=0
      ofs=0
      TextName=s
    end if
  end if
end method


method set(sys id, single ox, oy, sx, sy, sl, sys pt)
'====================================================
  '
  'STANDARD SETTINGS
  '
  ido=id      'identity number
  sclx=sx     'standard x scale
  scly=sy     'standard x scale
  xd=ox       'displacement from center
  yd=oy       'displacement from center
  ofs=0       'text line offset
  q=sy/sl     'number of lines in display buffer
  spd=.125    'scrolling speed factor
  '
  Curword="" : tx0="" : tx1="" : tx2="" 'temp strings
  '
  ndis=1 'flag new display
  '
  vpr=0.414        'viewport: y/x ratio
  'd=vpr*2*scly/q   'line scale size to number of lines in the display buffer
  d=sl*vpr*2       'line size
  ypd=0            'base padding
  'BlockSelAble=1
  '
  @txt=pt 'TEXT ARRAY OBJECT
  '
end method


method Anchor()
===============
pxd=xd
pyd=yd
pxc=sclx
pyc=scly
end method


method MoveScale(single nxd, nyd , nxc, nyc)
============================================
xd=pxd+nxd
yd=pyd+nyd
sclx=pxc*nxc
scly=pyc*nyc
end method


method enq()
'===========
  print recordof this
end method


'=======================
end class 'EditBoxObject
'=======================

'#recordof EditBoxObject


