  'WINUTIL.INC

  '14:53 23/09/2017
  '22:50 10/03/2018
  '17:38 29/01/2021
  '16:40 22/05/2023
  '12:36 30/04/2026
  '23:34 22/05/2026
  'CP

  #ifndef HAS_COREWIN
    uses corewin
  #endif
  '
  'string cr=chr(13,10)
  string ers 'error messages
  int    ert

  /*
  https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx

  BOOL WINAPI SystemParametersInfo(
  _In_    UINT  uiAction,
  _In_    UINT  uiParam,
  _Inout_ PVOID pvParam,
  _In_    UINT  fWinIni
  );

  'uiAction
  % SPI_GETWORKAREA     0x0030
  'fWinIni
  % SPIF_UPDATEINIFILE  0x01
  % SPIF_SENDCHANGE     0x02
  */

  int hpos,vpos,WaWidth,WaHeight
  int spinfo[4]
  scope
    SystemParametersInfo 0x0030,0,@spinfo,0
    indexbase 1
    WaWidth=spinfo[3]
    WaHeight=spinfo[4]
  end scope

  'not used
  'hpos=CW_USEDEFAULT
  'vpos=CW_USEDEFAULT
  '
  'OPTIONS FOR GUI STATE VARIABLES:

  'option:
  '% GuiStateServer 'SERVER SIDE
  'or
  'option:
  '% GuiStateClient 'CLIENT SIDE
  '
  'option:
  'ACTIVATE SHARING BETWEEN PROCESSES
  'BY USING NAMED SHARED MEMORY
  'case-sensitive, and must be 'Local'
  'this equate is set by both server and client apps
  '% GuiSharedMem  "Local\WinGuiState"
  '
  % GuiStateServer
  uses GuiInterface
  if ert
    mbox ers
  endif
  '
  running=1

  int    isRegistered
  int    minCreate, RebuildWindow
  int    _interval_
  int    _event_
  RECT   crect

  'already defined
  'string cr=chr(13,10), tab=chr(9), qu=chr(34)


  #ifndef width
    int width=640  'global
    int height=480 'global
  #endif

  #ifdef OpenGL
    function SelectPixelFormat(sys hDC,optional n) as int
    =====================================================

    static PIXELFORMATDESCRIPTOR pfd

    'setup pixel format
    pfd.nSize           = sizeof PIXELFORMATDESCRIPTOR 'Size of UDT structure
    pfd.nVersion        = 1                            'Version. Always set to 1.
    pfd.dwFlags         = PFD_DRAW_TO_WINDOW or _      'Support Window
                          PFD_SUPPORT_OPENGL or _      'Support OpenGL
                          PFD_DOUBLEBUFFER             'Support Double Buffering
    pfd.iPixelType      = PFD_TYPE_RGBA                'Red, Green, Blue, & Alpha Mode
    pfd.cColorBits      = 32                           '32-Bit Color Mode
    pfd.cRedBits        = 0                            'Ignore Color and Shift Bits...
    pfd.cRedShift       = 0                            '...
    pfd.cGreenBits      = 0                            '...
    pfd.cGreenShift     = 0                            '...
    pfd.cBlueBits       = 0                            '...
    pfd.cBlueShift      = 0                            '...
    pfd.cAlphaBits      = 0                            'No Alpha Buffer
    pfd.cAlphaShift     = 0                            'Ignore Shift Bit.
    pfd.cAccumBits      = 0                            'No Accumulation Buffer
    pfd.cAccumRedBits   = 0                            'Ignore Accumulation Bits...
    pfd.cAccumGreenBits = 0                            '...
    pfd.cAccumBlueBits  = 0                            '...
    pfd.cAccumAlphaBits = 0                            '... Good Cereal! ;)
    pfd.cDepthBits      = 24                           ' bits z-buffer depth 8 16 24
    pfd.cStencilBits    = 8                            'Stencil Buffer
    pfd.cAuxBuffers     = 0                            'No Auxiliary Buffer
    pfd.iLayerType      = PFD_MAIN_PLANE               'Main Drawing Plane
    pfd.bReserved       = 0                            'Reserved
    pfd.dwLayerMask     = 0                            'Ignore Layer Masks...
    pfd.dwVisibleMask   = 0                            '...
    pfd.dwDamageMask    = 0                            '...
    if n
      pixelForm = ChoosePixelFormat(hDC, @pfd) 'First without multisampling
    endif
    SetPixelFormat(hDC, PixelForm, @pfd)
    end function 'set antialias
    '
    function SelectMultiSample(sys hDC,ns) as int
    =============================================
    '
    'IDENTIFY MULTISAMPLING FORMAT
    'http://www.opengl.org/wiki/Creating_an_OpenGL_Context#Proper_Context_Creation
    int attribs[]=
    {
      0x2001,01,     'WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
      0x2010,01,     'WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
      0x2011,01,     'WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
      0x2013,0x202B, 'WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
      0x2014,24,     'WGL_COLOR_BITS_ARB, 24,
      0x201B,08,     'WGL_ALPHA_BITS_ARB, 08,
      0x2022,24,     'WGL_DEPTH_BITS_ARB, 24,
      0x2023,08,     'WGL_STENCIL_BITS_ARB, 08, 
      0x2041,01,     'WGL_SAMPLE_BUFFERS_ARB, 01, //Number of buffers (must be 1 at time of writing)
      0x2042,ns,     'WGL_SAMPLES_ARB, 04,        //Number of samples
      0x0000,00      'terminate list
    }
    sys p,a,n
    p=wglGetProcAddress "wglChoosePixelFormatARB"
    'https://registry.khronos.org/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt
    'BOOL wglChoosePixelFormatARB(HDC hdc,
    '                             const int *piAttribIList,
    '                             const FLOAT *pfAttribFList,
    '                             UINT nMaxFormats,
    '                             int *piFormats,
    '                             UINT *nNumFormats);
    if p
      call p(hdc, &attribs, null, 1, &a, &n)
      if n
        pixelForm=a
        return -1 'supporting multisample / antialias
      endif
    endif
    end function


    macro CreateMainWindowPass
    ==========================
    hwnd = CreateWindowEx( 
      0,                  'no extended styles           
      "wins",             'class name                   
      "Main Window",      'window name  
      style,              '                
      hpos,               'horizontal position  
      vpos,               'vertical position    
      width,              'window width                
      height,             'window height               
      null,               'no parent or owner window    
      null,               'class menu used              
      hinst,              'instance handle              
      null);              'no window creation data
    if not hWnd then
      MessageBox 0,"Unable to create window","problem",MB_ICONERROR
      exit function
    end if
    end macro
  '

    macro CreateMainWindow
    ======================
    minCreate=1 'pass for pixel format selection
    CreateMainWindowPass
    hDC=GetDC hwnd
    SelectPixelformat hDC,1 'Setup pfd then set pixelformat
    hRC = wglCreateContext hDC
    wglMakeCurrent hDC, hRC
    %% MultiSamples 4 'default
    if Multisamples
      SelectMultiSample hDC,MultiSamples
    end if
    wglDeleteContext hRC
    ReleaseDC hWnd,hDC
    DestroyWindow hWnd
    '
    'Recreate the main window with full initialisation
    '
    minCreate=0
    CreateMainWindowPass
    '
    end macro

  #endif 'Opengl
  '
  #ifndef OpenGL
    macro CreateMainWindow()
    ========================
    /*
    hwnd = CreateWindowEx(
      0,                  'extended styles           
      "wins",             'class name                   
      "Main Window",      'window name  
      style,              '                
      hpos,               'horizontal position  
      vpos,               'vertical position    
      width,              'window width                
      height,             'window height               
      null,               'no parent or owner window    
      null,               'class menu used              
      hInst,              'instance handle              
      null);              'no window creation data
    */
    hWnd = CreateWindowEx(0,"wins","Main Window",style,hpos,vpos,width,height,0,0,hInst,0)
    if not hWnd
      MessageBox 0,"Unable to create window","problem",MB_ICONERROR
      exit function
    endif
    end macro
  #endif
  '
  macro LogMousePos
  =================
  mposx=LoWord(lparam)
  mposy=HiWord(lparam)
  sPosX=mPosX : sPosY=mPosy
  'GetCursorPos @mp
  'sp=mp
  act=1
  end macro

  macro MouseMessages
  ===================
  case WM_MOUSEMOVE
    mposx=LoWord(lparam) : _event_=1
    mposy=HiWord(lparam)
    mmove=1
    if act=0 then act=1
    static POINT sp,mp
  case WM_LBUTTONDOWN : bleft=1 : _event_=1 : LogMousePos
  case WM_LBUTTONUP   : bleft=0  : _event_=1 eposx=mposx
  case WM_RBUTTONDOWN : bright=1 : _event_=1 : LogMousePos
  case WM_RBUTTONUP   : bright=0 : _event_=1 : eposx=mposx
  case WM_MBUTTONDOWN : bMid=1 : _event_=1   : LogMousePos
  case WM_MBUTTONUP   : bMid=0 : _event_=1   : eposx=mposx
  case WM_MOUSEWHEEL  : bWheel=wParam : _event_=1 : sar bWheel,16
  end macro


  macro KeyboardMessages
  ======================
  case WM_CHAR    : lastchar=wparam : _event_=1
  case WM_KEYUP   : key[wparam]=0 : _event_=1 : keyd=0 : if wparam>30 then bkey=0
  case WM_KEYDOWN
    _event_=1
    wparam and= 255
    select wparam
    #ifdef keydown
    keydown 'macro intercept
    #endif
    'DEFAULT CASES
    #ifndef NoEscape
    case 27 : SendMessage hwnd, WM_CLOSE, 0, 0
    #endif
    case 32 : if key[32]=0 then pause=1-pause 'toggle
    end select
    key[wparam]=1
    lastkey=wparam
    bkey=lastkey
    keyd=lastkey
    #ifdef opengl
    act=1
    #endif
  end macro


  'MICROSECOND TIMER
  ==================
  '
  macro TimeMark(c)
  =================
  QueryPerformanceCounter @c
  end macro
  '
  function TimeDiff(quad *te,*ts) as double
  =========================================
  static quad freq
  QueryPerformanceFrequency @freq
  return (te-ts)/freq 'SECONDS
  end function
  '

  function AppExePath(int n=0) as string
  ======================================
  static byte b[512]
  int i=GetModuleFileName(GetModuleHandle(0), @b, 512)
  while b[i] != 0x5c '92 '\'
    i--
  wend
  if not n then i++ 'include the '\' by default
  b[i]=0
  '= @b 'low level
  char bc at @b
  function=bc
  end function


  function GetClientWHXY(sys hWnd, *w,*h,*x,*y)
  =============================================
  RECT  rc
  POINT pt
  GetClientRect(hwnd, @rc)
  GetCursorPos @pt
  w=rc.right*.25
  h=rc.bottom
  ScreenToClient hWnd,@pt
  x=pt.x
  y=pt.y
  end function


  function GetDropFiles(sys hDropParam) As string
  ===============================================
  string sDropFiles, sFile
  int i,e,le
  e=DragQueryFile(hDropParam, -1, null, 0)-1
  '
  for i = 0 To e
    le=DragQueryFile(hDropParam, i, null, 1)
    sfile=space le              
    DragQueryFile(hDropParam, i, StrPtr sFile, le+1)
    If Ucase(mid(sFile, -4)) = ".LNK"
    else
      sDropFiles+= sFile + chr(13,10)
    end if
  next i   
  return sDropFiles
  end function


  /*

  =====
  NOTES
  =====

  STANDARD CHILD WINDOWS STYLES
  '
  "Button"    button.
  "ComboBox"  combo box.
  "Edit"      edit control.
  "ListBox"   list box.
  "MDIClient" MDI client window.
  2ScrollBar" scroll bar.
  2Static"    static control.




  BOOL WINAPI CreateProcess(
  1  __in_opt     LPCTSTR lpApplicationName,
  2  __inout_opt  LPTSTR lpCommandLine,
  3  __in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  4  __in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  5  __in         BOOL bInheritHandles,
  6  __in         DWORD dwCreationFlags,
  7  __in_opt     LPVOID lpEnvironment,
  8  __in_opt     LPCTSTR lpCurrentDirectory,
  9  __in         LPSTARTUPINFO lpStartupInfo,
  10 __out        LPPROCESS_INFORMATION lpProcessInformation
  );

  */

  '
  '
  macro MessageLoop()
  '==================
  '
  MSG wm
  int bRet
  '
  #ifdef opengl
    do 'frame processing loop
    while PeekMessage @wm, 0, 0, 0, PM_REMOVE
  #else
    while bRet := GetMessage @wm, 0, 0, 0
  #endif
  '
  'if bRet == -1 then
  '  'show an error message?
  'else
    #ifdef EscapeKeyEnd
      if wm.message=WM_KEYDOWN
        if wm.wparam=27
          SendMessage hwnd,WM_CLOSE,0,0
        end if  
      end if
    #endif
    '
    #ifdef InMessageLoop
      InMessageLoop ''CUMSTOMISED MESSAGE PROCESSING
    #else
      #ifdef MessageLoopProcesses
        MessageLoopProcesses
      #endif
      TranslateMessage @wm
      DispatchMessage @wm
    #endif
  wend 'GetMessage / PeekMessage
  '
  #ifdef Opengl
    if not running
      exit do
    endif
    #ifdef ActOpengl
      ActOpengl 'frame processing
    #endif
    loop 'each frame
    running=1 'READY FOR ANOTHER WINDOW
  #endif
  end macro
  '
  extern
  ======

  declare * _main_

  --------------
  def MakeWindow
  ==============
  #ifdef Main
    @_main_=@main
  #endif
  '
  #ifndef WndProc
  '
  function WndProc(sys hWnd, wMsg, wParam,lParam) as sys callback
  '
  static sys hdc, htimer
  static RECT crect
  static int ID_Timer=1000
  '
  subroutine gomain
    if @_main_ 'user defined callback
      _main_(hWnd,wMsg,wParam,lParam)
    endif
  end subroutine
  '
  select wMsg
  '
  incl MouseMessages
  incl KeyBoardMessages
  '
  case WM_MOVE
    gosub gomain
  case WM_SIZE
    gosub gomain
  case WM_PAINT
    gosub gomain
  case WM_TIMER
    gosub gomain
  case WM_CREATE
    opening=1
    gosub gomain
    if _interval_ > 0
      hTimer = SetTimer hWnd, ID_Timer, _interval_, 0
    endif
    GetClientRect  hWnd,@cRect
    opening=0
  case WM_DESTROY
    closing=1
    gosub gomain
    if _interval_ > 0
      KillTimer(hWnd,ID_Timer)
    endif
    closing=0
    PostQuitMessage 0
  case else
    _event_ = 0
    function=DefWindowProc hWnd,wMsg,wParam,lParam
  end select
  if _event_ 'mouse/keyboard
    gosub gomain
   _event_=0
  endif
  end function ' WndProc
  '
  #endif 'ndef wndproc
  MainWindow(%1)
  end def 'MakeWindow
  '
  '
  ====================
  Function MainWindow(
     int width=width,
         height=height, 
         style=WS_OVERLAPPEDWINDOW,
         place=2,
     int interval=0
    )
  ====================
  indexbase 0
  '
  'assign to global
  prior width=width   'local width
  prior height=height 'local height
  _interval_=interval
  '
  select place 'default, left, centre, right
  case 0 : hpos=32 : vpos=32
  case 1 : hpos=0: vpos=0
  case 2 : hpos=(wawidth-width)>>1 : vpos=(WaHeight-height-32)>>1
           if vpos<0 then vpos=0
  case 3 : hpos=wawidth-width-6 : vpos=0
  end select
  '
  int      a,b,c
  sys      hWnd
  'globals hDC, hRC, hInst, minCreate
  '
  hInst=GetModuleHandle 0 'global
  inst=hInst 'legacy
  string cname="wins"
  '
  if not isRegistered
  WNDCLASSEX wc
  with wc
    .cbSize        = sizeof WNDCLASSEX                 '
    .style=CS_HREDRAW or CS_VREDRAW
   '.style = CS_DBLCLKS | CS_OWNDC
    .lpfnWndProc   = @WndProc
    .cbClsExtra    = 0
    .cbWndExtra    = 0    
    .hInstance     = hInst
    .hIcon         = LoadIcon 0, IDI_APPLICATION
    .hCursor       = LoadCursor 0,IDC_ARROW
    .hbrBackground = GetStockObject WHITE_BRUSH
    .lpszMenuName  = 0
    .lpszClassName = strptr cname
    .hIconSm       = null
  end with
  if not RegisterClassEx @wc
    MessageBox 0,"Registration failed","Problem",MB_ICONERROR
    'exit function
  end if
  isRegistered=1 
  endif 'not isregistered
  '
  CreateMainWindow 'MACRO WITH OPENGL OVERRIDE
  '
  DragAcceptFiles(hwnd, true)
  '
  #ifdef WindowOpacity 'transparen translucen
    'Set WS_EX_LAYERED on this window 
    SetWindowLong(hwnd, GWL_EXSTYLE,
    GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED)
    SetLayeredWindowAttributes(hwnd, 0, WindowOpacity, LWA_ALPHA);
  #endif
  '
  ShowWindow hWnd,SW_NORMAL
  UpdateWindow hWnd
  hWndMain=hwnd 'global
  MessageLoop()
  if GuiMemHandle
    if GuiMemBuffer
      UnmapViewOfFile(GuiMemBuffer)
    endif
    CloseHandle(GuiMemHandle)
  endif
  '
  end function ' end MainWindow

  end extern
  ==========


  sub UnregisterMain()
  ====================
  UnregisterClass "wins",hInst
  isRegistered=0
  end sub
