  typedef struct tagWINDOWPLACEMENT {
  UINT  length;
  UINT  flags;
  UINT  showCmd;
  POINT ptMinPosition;
  POINT ptMaxPosition;
  RECT  rcNormalPosition;
  RECT  rcDevice;
  } WINDOWPLACEMENT;


  indexbase 1

  function SetFont(sys *hwnd,int n,height,width,weight, string fontname) as sys
  =============================================================================
  sys hFont
  int i
  hfont=CreateFont( height,width,0,0,weight,0,0,0,0,0,0,0,0,fontname)
  for i=1 to n
    SendMessage hwnd(i),WM_SETFONT,hfont,0
  next
  return hFont
  end function

 
  % ID_FIRSTCHILD  100 'Each window 100... 
  sys hinst=GetModuleHandle 0
  asciiz * cmdline 
  @cmdline=GetCommandLine

  ======================================


  'STANDARD CHILD WINDOWS STYLES
  '=============================
  '
  'Button	The class for a button.
  'ComboBox	The class for a combo box.
  'Edit	        The class for an edit control.
  'ListBox	The class for a list box.
  'MDIClient	The class for an MDI client window.
  'ScrollBar	The class for a scroll bar.
  'Static	The class for a static control.



  function GetSelTextLine(sys h) as string
  ========================================
  sys b
  int je,le,st,en
  static string s
  s=nuls 512
  b=strptr(s)
  *b=512 'put buffer length info into buffer string
  SendMessage h, EM_GETSEL, @st, @en       'LOCATE CARET / SELECTED AREA
  je=SendMessage h, EM_LINEFROMCHAR, st, 0 'IDENTIFY LINE
  st=SendMessage h, EM_LINEINDEX, je, 0    'LOCATE START OF LINE
  le=SendMessage h, EM_GETLINE, je, b      'GET LINE STRING AND LENGTH
  SendMessage h,EM_SETSEL,st,st+le         'HIGHLIGHT LINE
  return left s,le                         'RETURN LINE STRING
  end function


  sub SetSelColor(sys hd, int c)
  ==============================
  CHARFORMATA cf 'charformatW
  cf.cbsize=sizeof(cf)
  SendMessage hd,EM_GETCHARFORMAT,SCF_SELECTION,@cf
  cf.dweffects and= not(CFE_AUTOCOLOR)
  cf.crTextColor = c
  SendMessage hd,EM_SETCHARFORMAT,SCF_SELECTION,@cf
  end sub


  sub AdjustForCRLF(string *s, int *a)
  ====================================
  int i,c
  do
    i=instr(i+1,s,chr(13,10))
    if i=0
      exit do
    endif
    if i<a
      c++
    else
      exit do
    endif
  loop
  a-=c
  end sub


  function PostFileContent(string *f,sys hl,hd) as int
  ====================================================
  int a
  string s,sl
  f=GetSelTextLine hl
  if f
    s=getfile f
    sl=lcase s
    a=SearchString sl
  else
    s=chr 0
    a=0
  endif
  '
  SendMessage hd, WM_SETTEXT, 0 , s
  '
  AdjustForCRLF(s,a)
  if a>0 
    a-=1
  endif
  'SetSelColor hd,0xf00040
  SendMessage hd,EM_SETSEL,a,a
  'SendMessage hd, EM_SCROLLCARET, 0, 0
  return a
  end function


  function GetTextFromWindow(sys h,int *e) as string
  ==================================================
  int a
  a=SendMessage h, WM_GETTEXTLENGTH,0,0
  function=nuls a
  e=SendMessage h, WM_GETTEXT,a+1 , strptr(function)
  function=left function,e
  end function


  function LocateHighlightKeyword(sys hl,hd, int le) as int
  =========================================================
  int a,e
  a=val GetSelTextLine hl
  string s
  s=GetTextFromWindow(hd,e)
  AdjustForCRLF(s,a)
  if a>0
    a-=1
  endif
  'SendMessage hd,EM_SETSEL,a,a+le
  'SetSelColor hd,0xff2040
  SendMessage hd,EM_SETSEL,a,a+le
  SendMessage hd, EM_SCROLLCARET, 0, 0
  return a
  end function


  function PostLocationList(sys hd, string f)
  ===========================================
  string s,sl
  s=""
  if wordlist
    if f
      s=getfile f
      sl=lcase s
      s=KeywordPosList sl
    endif
  endif
  '
  SendMessage hd, WM_SETTEXT, 0 , *s
  '
  end function

sub GetBasicWord(string*bu,int*i)
=================================
  int a,j
  byte bt at strptr(bu)
  sttw=i
  do
    ascb=bt[i]
    select ascb
    case 0 to 32
      exit do
    case 0x30 to 0x39 'numbers
    case 0x41 to 0x5a 'uppercase
      bt[i]+=32       'to lowercase
    case 0x61 to 0x7a 'lowercase
    case 0x80 to 0xff 'higher ascii
    case 35,46,95
    case 34,96
      a=bt[i]
      j=i+1
      'skio over quote
      do
        i++
        select bt[i]
        case 0
          i=j
          a=0
          exit do
        case a
          i++
          exit do
        end select  
      loop
      'a=instr i,bu,chr(a)
      if a
        exit do
      endif
      continue do
    case else
      if i=sttw
        i++
      endif
      exit do
    end select
    i++
  loop
  lenw=i-sttw
end sub

sub colorize(sys h)
===================
  '
  fvp=fvc
  '
  int a,b,c,d,e,g,i,j
  int line
  int se[7]
  string wr,bu
  static int mpl[255]
  static string keyw
  line = SendMessage(h,EM_GETFIRSTVISIBLELINE,0,0)
  fvc = SendMessage(h,EM_LINEINDEX,line,0)
  fvp=fvc
  'if fvc
  SendMessage(h,EM_EXGETSEL,0,@se[2])
  'saves current selection
  SendMessage(h,EM_HIDESELECTION,1,0)
  'clear sel
  SendMessage(h,EM_EXSETSEL,0,@se[0])
  se[0]=fvc
  se[1]=fvc+0x1000
  'SendMessage(h,EM_EXSETSEL,0,@se)
  'select part of visible text
  if not keyw
    keyw=getfile "inf/keywordsSorted.txt"
    if not keyw
      goto excolorize
    endif
    i=1
    b=0
    e=len(keyw)
    'map keyw by first ascii
    'must start with blank line
    'must exclude ' ascii 39 40 41 59
    do
      skiplspace(keyw,i) 'ascb
      sttw=i
      endline(keyw,i)
      if i=sttw
        i+=2
      endif
      if i>=e
        exit do
      endif
      if b<ascb
        b=ascb 'start of new ascii group
        mpl(b)=sttw
      endif
    loop
  endif
  int n
  bu=GetTextFromWindow h,n
  'clears existing coloring
  SendMessage h,WM_SETTEXT,0,""
  SendMessage h,WM_SETTEXT,0,strptr(bu)
  i=1
  c=0
  d=0
  e=0
  do
    skiplspace(bu,i)
    if ascb=13
      e++
      i+=2
      continue do
    endif
    select ascb
    case 39,59
      endline (bu,i) 'BASIC or ASM comment
      continue do
    case 47
      a=asc(bu,i+1)
      if a=42
        g=instr(i,bu,"*/") 'skip C comment
        if g
          do
            endline(bu,i)
            if i>g
              i=g+2
              exit do
            endif
            i+=2
            e++
          loop
        endif
        continue do
      elseif a=47 'skip C line comment
        endline(bu,i)
        continue do
      endif
    end select
    '
    GetBasicword(bu,i)
    '
    if lenw<1
      goto excolorize
    elseif lenw<2
      'heuristic ignore symbols
      continue do
    endif
    wr=mid bu,sttw,lenw
    'multiline quotes / crlf
    if (ascb=34)or(ascb=96)
      j=1
      do
        endline(wr,j)
        if asc(wr,j)=13
          j+=2
          e++
        else
          exit do
        endif
      loop
    endif
    c++
    a=asc wr
    a=mpl(a)
    if a=0
      continue do
    endif
    '
    lookon:
    =======
    '
    g=instr(a,keyw,wr)
    if g
      b=asc(keyw,g-1)
      if b>32
        a+=1
        goto lookon
      endif
      b=asc(keyw,g+lenw)
      if b>32
        a=g+lenw
        goto lookon
      endif
      d++
      b=sttw
      b--
      b-=e 'correctforcr
      'partial coloring
      'a=fvp+1000
      'if b>fvp and b<a
        se[4]=b
        se[5]=b+lenw
        SendMessage(h,EM_EXSETSEL,0,@se[4])
        SetSelColor h,0xFF4040
        '
        'testing EM_GETSELTEXT & EM_EXSETSEL
        'wstring wwr=nuls 32
        'SendMessageW(h,EM_GETSELTEXT,0,wwr) 'always wide-chars
        'wr=wwr
        'print wr
        'SendMessage(h,EM_EXSETSEL,0,@se[2])
      'endif
    endif
  loop
  'alt EM_REPLACESEL
  '
  excolorize:
  ===========
  SendMessage(h,EM_EXSETSEL,0,@se[2]) 'restore prior selection
  SendMessage(h,EM_HIDESELECTION,0,0)
end sub



  =================================================================
  function WndProc(sys hwnd, uMsg, wParam, lParam) as long callback
  =================================================================
  '
  indexbase 0

  static RECT rcClient 
  static sys a,b,c,
    h,i,px,py,lx,ly,id,
    style,stylr,
    newfile,wfocus
  static sys ce=-1, pe=-1
  static sys hfont[4]
  '
  static string s,f,cf,fnt,st,ff
  if wfocus=101 'FILE LIST
    a=0xffff and SendMessage w[1], EM_GETSEL, 0, 0 'loword
    if a<>ce
      ce=a
      f=GetSelTextLine w[1]
      if f<>cf
        PostLocationList w[2],f
        a=PostFileContent f,w[1],w[3]
        'ce=0xffff and SendMessage w[1], EM_GETSEL, 0, 0 'loword
        'LocateHighlightKeyword w[2],w[3],len wordlist
        cf=f
      endif
    endif
  elseif wfocus=102 'KEYWORD LOCATION LIST
    a=0xffff and SendMessage w[2], EM_GETSEL, 0, 0 'loword
    if a<>pe
      pe=a
      a=LocateHighlightKeyword w[2],w[3],len wordlist
      '
      'display line number
      int je
      je=SendMessage w[3], EM_LINEFROMCHAR, a, 0 'IDENTIFY LINE
      SendMessage w[5],WM_SETTEXT, 0, str(je+1) 
    endif
  elseif wfocus=105 'LINE NUMBER
    'goproc
  endif
 
  select uMsg

  case 0x200 to 0x20A 'MOUSE MESSAGES
    '
    scope
    static RECT  rcw
    static POINT mp
    GetWindowRect hchw,rcw
    GetCursorPos mp
    if mp.x>=rcw.left 'MOUSE OVER HCHW VIEWPORT
      mposx=mp.x-rcw.left
      mposy=mp.y-rcw.top
      '
      macro LogMousePos
      =================
      sPosX=mPosX : sPosY=mPosy
      act=1
      end macro

      select uMsg
      case WM_MOUSEMOVE
        mmove=1
        if act=0 then act=1
      case WM_LBUTTONDOWN : bleft=1  : LogMousePos
      case WM_LBUTTONUP   : bleft=0  : eposx=mposx
      case WM_RBUTTONDOWN : bright=1 : LogMousePos
      case WM_RBUTTONUP   : bright=0 : eposx=mposx
      case WM_MBUTTONDOWN : bMid=1   : LogMousePos
      case WM_MBUTTONUP   : bMid=0   : eposx=mposx
      case WM_MOUSEWHEEL  : bWheel=wParam : sar bWheel,16
      end select
      return 0
    endif
    end scope

  
  case WM_COMMAND
  ===============

    select wParam
    '
    case 4001 'SEARCH (F3)
    ======================
    '
    wholeword=0
    gosub DoSearch
    '
    case 4002 'Save File (F9)
    =========================
    '
    if len cf
      s=GetTextFromWindow w[3],a
      putfile cf,s
      SetWindowText hwnd, cf " saved"
    endif
    '
    case 4003 'Exec File (F5)
    =========================
    '
    if len cf
      scope
      string sd=nuls(256)
      GetCurrentDirectory 256,sd
      sd=rtrim sd
      string sp=dirpath(cf,1)
      if sp
        SetCurrentDirectory(sp)
      endif
      string f=qu+trimpath(cf)+qu
      if right(cf,6)=".o2bas"
        'Exec(sd+"\co2.exe "+f,0) 'assume co2 path
        'grafide
        string sc
        sc=AppExePath()
        QuExec(sc+"co2.exe","",f)
        SetWindowText hwnd, cf " Exec"
      elseif right(cf,4)=".bat"
        DOS(f,0)
        SetWindowText hwnd, cf " Exec"
      elseif right(cf,4)=".obj"
        #ifdef ObjFileName
          ObjFileName=trimpath(cf)
          'EXEC FROM FILE
          'BuildObj()
          'EXEC FROM WINDOW SCRIPT
          int a
          s=GetTextFromWindow w[3],a
          ObjBuilder b
          b.CompileObj(s)
          s=""
        #endif
      endif
      SetCurrentDirectory(sd)
      end scope
    endif
    '
    case 4004 'WORD SEARCH (F4)
    ===========================
    '
    wholeword=1
    gosub DoSearch
    '
    '
    case 4005
    =========
    '
    'pvc=1-pvc 'toggle line numbering
    '
    colorize w[3]

    end select

    '
    if hiword(wparam)=EN_SETFOCUS
      wfocus=loword(wparam)
    endif
    return 0
 
 
  case WM_CREATE
  ==============
  '
  'SETUP DEVICE CONTEXT AND RENDER CONTEXT
  '
  if minCreate
    return DefWindowProc(hwnd, uMsg, wParam, lParam) 'unprocessed messages
  endif
  SetTimer hWnd,1,10,null
  int style=WS_CHILD | WS_VISIBLE '| WS_BORDER
  int id=ID_FIRSTCHILD+100
  hchw=CreateWindowEx(0,"static", null, style, 0,0,0,0, hwnd, id, hInst, null)
  if hchw
    hDC=GetDC hchw
    SelectPixelformat(hDC)
    hRC = wglCreateContext hDC
    wglMakeCurrent hDC, hRC
    SetFun wglSwapIntervalEXT
  endif
  #ifndef opengles
  if hrc
    #ifdef fontA
      BuildFont hWnd, hDC, hRC, 1024,"Arial",FW_NORMAL,0
    #endif
    #ifdef fontB
      BuildFont hWnd, hDC, hRC ,1280, "Courier New",600,1
      'BuildFont hWnd, hDC, hRC ,1280, fontB
    #endif
  endif
  #endif
  '
  'SYNC FRAME RATE - 60HZ
  'sys p=wglgetprocaddress "wglSwapIntervalEXT" : call p 1
  if @wglSwapIntervalEXT
    wglSwapIntervalEXT 1
  end if
  '
  FrameCount=0
  Initialize hWnd
  ' SetWindowText hwnd,title
  ' SET PRECISE CLIENT AREA
  ' RECT rc
  ' GetClientRect hwnd,rc
  ' MoveWindow hWnd,hpos,vpos, width*2-rc.right, height*2-rc.bottom,1

  ' Create child windows.
  style=WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_NOHIDESEL
  stylr=style | ES_READONLY
  int idmenu
  idmenu=0
  id=ID_FIRSTCHILD
  py=0 : ly=0
  px=0 : lx=0
  '
  w[0]=CreateWindowExW(0,l"RichEdit50W", null, style, px,py,lx,ly, hwnd, id, hinst, null)
  w[1]=CreateWindowEx 0,"edit", null, stylr, px,py,lx,ly, hwnd, id+1, hinst, null
  w[2]=CreateWindowEx 0,"edit", null, stylr, px,py,lx,ly, hwnd, id+2, hinst, null
  w[3]=CreateWindowExW(0,l"RichEdit50W", null, style, px,py,lx,ly, hwnd, id+3, hinst, null)
  '
  SendMessage w[3],EM_LIMITTEXT,0x100000,0 '1 meg limit
  'a=SendMessage w[3],EM_GETLIMITTEXT,0,0 ' = &HC5 limit for XP.. 7fffffff (before: XP 7fff)
  'print a
  sys h=w[3]
  '
  id=104 : i=4 : px=10 : lx=10 : py=10 : ly=10
  style=WS_CHILD | WS_BORDER | WS_VISIBLE
  stylr=style | ES_READONLY

  'for keywords:
  w[4]=CreateWindowEx 0,"edit", null, style, px,py,lx,ly, hwnd, id+4, hinst, null
  'for line number
  w[5]=CreateWindowEx 0,"edit", null, style, 0,0,0,0, hwnd, id+5, hinst, null

  'action buttons
  style=WS_CHILD | BS_TEXT | BS_PUSHBOX | WS_VISIBLE
  w[6]=CreateWindowEx(0,"button", "find",  style, 0,0,0,0, hwnd, 4001, hinst, null)
  w[7]=CreateWindowEx(0,"button", "color", style, 0,0,0,0, hwnd, 4005, hinst, null)
  w[8]=CreateWindowEx(0,"button", "save",  style, 0,0,0,0, hwnd, 4002, hinst, null)
  w[9]=CreateWindowEx(0,"button", "exec",  style, 0,0,0,0, hwnd, 4003, hinst, null)
  '
  % EC_LEFTMARGIN 1
  '
  SendMessageW(w[3],EM_SETBKGNDCOLOR,0,0xeeffff)
  SendMessageW(w[3],EM_SETMARGINS,EC_LEFTMARGIN,10)
  int scid
  scid = id+3
  SetWindowSubClass(w[3],@EdProc,@scid,0)
  scid = id+5
  SetWindowSubClass(w[5],@GoProc,@scid,0)

  'SetFont(sys *hwnd,n,height,width,weight,string fontname) as sys
  hFont[1]=SetFont(w[0],3,12,8,400,"Lucida Console")
  hFont[2]=SetFont(w[3],1,14,10,400,"Lucida Console")
  hFont[3]=SetFont(w[4],5,14,10,400,"Lucida Console")


  ff=getfile cfgs
  '
  if not ff
    ff="'Default list"+cr+"-r .\*.o2bas"+cr+"-r .\*.inc"+cr+"-r .\*.txt"
  endif
  SendMessage w[0],WM_SETTEXT,0,*ff

  return 0

  case WM_TIMER
  =============
    act=2
    'actopengl
    return 0

  case WM_DROPFILES
  =================
    filedrop = rtrim GetDropFiles(wparam)
    DragFinish(wparam)
    return 0

  case WM_SIZE
  ==========
  'Set the window order
  'https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos
  '
  'sys hw=-1 'HWND_TOPMOST 'hw must be sys as a window handle
  'SetWindowPos(hwnd,hw,0,0,0,0,0x3)
 
  GetClientRect(hwnd, @rcClient) 
 
  'Size and position the child window.  
  int a,i,v,vb,gvx
  a=rcClient.right>>1
  for i=0 to 9
    v=rcClient.right>>2
    if v>160
      v=160
    endif
    vb=v*i
    if i<4
      if i=0
        v*=.75 'for search groups window
      elseif i=1
        vb=v*.75
        v*=1.25 'for files paths window
      elseif i=2
        v=v>>1 'for line numbers window
      elseif i=3
        vb-=v\2
        v=(rcClient.right-vb) >> 1 ' script window
      endif
      MoveWindow(w[i], vb, 30, v-5, rcClient.bottom-60, true)
      gvx=vb+v 
    else 'i>=4
      if i=4
        'keyword entry
        a=240
        MoveWindow(w[4], 0, 5, a-20, 20, true)
      endif
      if i=5
        'line number display
        MoveWindow(w[5], a, 5,70, 20, true)
        a+=80
      endif
      if i>5
        'action buttons
        MoveWindow(w[i], a, 5,55, 20, true)
        a+=60
      endif
    endif
    '
    'ShowWindow(w[i], SW_SHOW)
  next
  if hchw
    'act=4
    int vpw=rcClient.right-gvx-5
    int vph=rcClient.bottom-60
    MoveWindow(hchw, gvx, 30,vpw,vph, 0) 
    getClientRect(hchw,@crect)
    glViewport 0,0, vpw, vph
    aspect=vpw/vph  'WIDTH/HEIGHT
    'scope
    'WINDOWPLACEMENT wp
    'wp.length=sizeof wp
    'GetWindowPlacement hwnd,wp
    'RECT wr
    'wr=wp.rcNormalPosition
    'GetWindowRect hchw,wr
    'end scope
    #ifndef opengles
      setPerspective
    #endif
    ActOpengl 'CONTINUOUS REFRESH
  endif
  return 0 

  case WM_CLOSE
  ============= 

  h=w[0]
  KillTimer hwnd,1
  ff=GetTextFromWindow h,a
  putfile cfgs,ff
  DestroyWindow(hwnd)
  return 0 

  case WM_DESTROY:
  ================
  '
  if minCreate then exit function
  if not running then exit function 'PREVENT RECURSION
  act=5
  'scene hwnd   'final frame      
  'swapBuffers hdc
  Release hWnd 'cleanup
  #ifndef opengles
    #ifdef fontA
      glDeleteLists 1024, 256
    #endif
    #ifdef fontB
      glDeleteLists 1280, 256
    #endif
  #endif
  wglMakeCurrent hDC, null
  wglDeleteContext hRC
  ReleaseDC hchw,hDC
  running=0 : act=0 : opening=1 : closing=0 : pausing=0
  DeleteObject hfont[1]
  DeleteObject hfont[2]
  DeleteObject hfont[3]
  DestroyWindow hWnd 'SELF DESTRUCT
  return 1
 
  end select
  '
  return DefWindowProc(hwnd, uMsg, wParam, lParam)
  '
    ===================
    subroutine DoSearch
    ===================
    '
    int a,b,c,d,e,aa,bb
    st=GetTextFromWindow w[4],a
    wordlist=lcase st
    c=len(st)
    SendMessage w[4], EM_SETSEL, 0, c
    SendMessage w[0], EM_GETSEL, @b, @c
    ff=GetTextFromWindow w[0],a
    SendMessage w[0], WM_SETTEXT, 0, ff
    b++
    d=1
    e=1
    do
      c=asc(ff,d)
      select c
        case 0 : exit do
        case 10 : e=d+1 : b++ 'adjust position for lf
      end select
      if d>=b
        exit do
      endif
      d++
    loop
    b=e 'StartOfLine ff,b
    a=instr(b,ff,cr+cr)
    if a=0
      a=len(ff)+1
    endif
    aa=a
    bb=b
    AdjustForCRLF ff,b
    AdjustForCRLF ff,a
    SendMessage w[0], EM_SETSEL, b , a
    SetSelColor w[0],0x4040F0
    SendMessage w[0], EM_SETSEL, b , b
    ff=mid ff,bb,aa+2-bb
    SetFocus w[4]
    s=GetFilteredFileLists ff
    SendMessage w[1], WM_SETTEXT, 0 , s 'file list
    SendMessage w[1], EM_SETSEL, 0 , 0
    f=GetSelTextLine w[1]
    'if f<>cf
    PostLocationList w[2],f
    a=PostFileContent f,w[1],w[3]
    'LocateHighlightKeyword w[2],w[3],len wordlist
    cf=f
    'endif
    ce=0
    SetFocus w[4]
    end subroutine
    '
  end function

