MDIGUI statement

Purpose:

The MDIGUI statement specifies that the program is a Multiple Document Interface Graphical User Interface application. Like the GUI statement, MDIGUI must provide a ClassName for the program.

As well as the MDIGUI statement, minimal BCX MDIGUI program must have a SUB FORMLOAD ... END SUB section and as well a BEGIN MDIEVENTS ... END MDIEVENTS section.

Syntax:

MDIGUI ClassName AS STRING [,PIXELS, ICON, ResInt AS INTEGER]

Parameters:

  • Data type: STRING
    ClassName A unique string literal name for the program. Every Windows MDIGUI program requires a ClassName. Windows uses the ClassName to distinguish one running program from another.
  • Data type: Argument
    PIXELS [OPTIONAL] Argument indicating that pixels instead of dialog units are to be used in the placement and size arguments locating the control.
  • Data type: Argument
    ICON [OPTIONAL] Argument indicating that an icon is to be loaded as a resource.
  • Data type: INTEGER
    ResInt Used with ICON, specifies an integer value to an icon resource type defined in an .rc file or as a BCX_RESOURCE.

Remarks:

The MDIGUI ClassName statement must be placed at the start of your program. The MDIGUI statement cannot be placed inside any SUB, FUNCTION nor within the BEGIN MDIEVENTS ... END MDIEVENTS loop. It must be placed at the file scope level, the same level at which your directives and global variables are declared.

In a BCX MDIGUI program, expressions must be inside a FUNCTION, SUB or the BEGIN MDIEVENTS ... END MDIEVENTS procedure.

When a BCX MDIGUI NOMAIN program is translated, a WNDCLASSEX structure named BCX_WNDCLASS is created and declared GLOBAL. It is initialized to the default values in the internal BCX translator BCX_InitGUI procedure and then registered using the internal BCX translator BCX_REGWND procedure. BCX_REGWND checks to see if a window class of the name being registered has already been used and if so does not register it again. It allows 256 different (non case sensitive) window classes to be registered. It also sets the BCX_GUI_INIT variable to TRUE, indicating that the procedure has been run and it will exit without doing anything next time it is called.

Example:

The following is a minimal BCX MDIGUI program. Save the example code below as mdigui.bas.

Save the following batch file, as Build.bat, into the same directory as mdigui.bas and run Build.bat to compile and run the example.

Build.bat Compilation Batch file:

CALL povars64.bat
bc mdigui

mdigui.bas

'---------------------------------------------------
MDIGUI "MDIName", PIXELS, ICON, 123
'---------------------------------------------------

$IPRINT_OFF

$COMPILER "$PELLES$\Bin\pocc -W1 -Gd -Go -Ze -Zx -Tx64-coff $FILE$.c"

$LINKER "$PELLES$\Bin\polink _
                    -release _
               -machine:X64 _
          -subsystem:windows _
             -OUT:$FILE$.exe _
                  $FILE$.obj _
                $FILE$__.res"

$RESOURCE "$PELLES$\bin\porc.exe"
 
$BCX_RESOURCE
  #define IDM_NEW           200
  #define IDM_EXIT          201
  #define IDM_WINDOWTILE    202
  #define IDM_WINDOWCASCADE 203
  #define IDM_WINDOWICONS   204
  #define ID_MAINMENU       205

  ID_MAINMENU MENU DISCARDABLE
  BEGIN
    POPUP "&File"
      BEGIN
        MENUITEM "&New",          IDM_NEW
        MENUITEM "E&xit",         IDM_EXIT
      END
    POPUP "&Window"
      BEGIN
        MENUITEM "&Tile",         IDM_WINDOWTILE
        MENUITEM "&Cascade",      IDM_WINDOWCASCADE
        MENUITEM "Arrange &Icons",IDM_WINDOWICONS
      END
  END
$BCX_RESOURCE

MACRO IDM_NEW           = 200
MACRO IDM_EXIT          = 201
MACRO IDM_WINDOWTILE    = 202
MACRO IDM_WINDOWCASCADE = 203
MACRO IDM_WINDOWICONS   = 204
MACRO ID_MAINMENU       = 205

DIM Form1 AS HWND        ' Main window handle
DIM hwndMDIClient AS HWND ' Mdi client window handle

SUB FORMLOAD()
  DIM RAW Style AS INTEGER

  Style = WS_MINIMIZEBOX BOR _
  WS_CLIPSIBLINGS BOR _
  WS_CLIPCHILDREN BOR _
  WS_MAXIMIZEBOX BOR _
  WS_CAPTION BOR _
  WS_BORDER BOR _
  WS_SYSMENU BOR _
  WS_THICKFRAME

  Form1 = BCX_FORM("MDI", 0, 0, 300, 300, Style)

  'Attach the main menu
  SetMenu(Form1,LoadMenu(BCX_HINSTANCE, MAKEINTRESOURCE(ID_MAINMENU)))

  ' BCX_MDICLASS takes the name of the callback function
  ' and the name of the class
  BCX_MDICLASS((WNDPROC)MdiChildWndProc, "MdiChildWndClass")

  ' The second parameter is the index of the main menu
  ' you want to attach "Untitled1"
  hwndMDIClient = BCX_MDICLIENT(Form1, 2)

  CENTER(Form1)
  SHOW(Form1)
END SUB

'---------------------------------------------------

CALLBACK FUNCTION WndProc ()
  SELECT CASE Msg

    CASE WM_CREATE

    CASE WM_COMMAND

    SELECT CASE wParam
 
      CASE IDM_NEW
      ' Use a character string if you do not want
      ' the default "untitled%d" title
      ' The second parameter is the name of class
      ' used in BCX_MDICLASS
      BCX_MDICHILD("", "MdiChildWndClass")

      CASE IDM_WINDOWTILE
      SendMessage(hwndMDIClient, WM_MDITILE, 0, 0)

      CASE IDM_WINDOWCASCADE
      SendMessage(hwndMDIClient, WM_MDICASCADE, 0, 0)

      CASE IDM_WINDOWICONS
      SendMessage(hwndMDIClient, WM_MDIICONARRANGE, 0, 0)

      CASE IDM_EXIT
      PostMessage(hWnd,WM_CLOSE,0,0)

    END SELECT

    CASE WM_DESTROY
    PostQuitMessage(0)

  END SELECT

  FUNCTION = DefFrameProc(hWnd, hwndMDIClient, Msg, wParam, lParam)
END FUNCTION

'---------------------------------------------------------- 

CALLBACK FUNCTION MdiChildWndProc ()
  SELECT CASE Msg
    CASE WM_CREATE
  END SELECT

  FUNCTION = DefMDIChildProc(hWnd, Msg, wParam, lParam)
END FUNCTION

BEGIN MDIEVENTS ... END MDIEVENTS statements

Purpose:

In a MDIGUI program, code that is responsible for monitoring and responding to messages and commands like mouse clicks, button presses, radio controls and so on is placed in the BEGIN MDIEVENTS ... END MDIEVENTS block.

It is important to remember that this block is a callback routine which can be called several times before any specific task contained in the block is completed. For this reason, it is best that any variables which must be declared in the BEGIN MDIEVENTS ... END MDIEVENTS block, should be declared as STATIC or DIM RAW. When DIM or LOCAL are used, BCX emits code to automatically clear the variable to zero and so if a callback occurs before a task is completed the DIM or LOCAL variables will be cleared to zero and the task will fail.

Syntax:

BEGIN MDIEVENTS ProcedureName
  ' Messages and Commands
END MDIEVENTS [MAIN]

Parameters:

  • Data type: Identifier
    ProcedureName The unquoted name for the MDIEVENTS loop.
    👉 The loop must be named.
  • Data type: Argument
    MAIN [OPTIONAL] Used when there is more than one event loop in the program, to indicate that this instance of the END MDIEVENTS statement is the end of the main program.

Remarks:

This BCX code,

BEGIN MDIEVENTS ProcedureName
  SELECT CASE CBMSG
  CASE WM_LBUTTONDOWN
    SetWindowText(Stat1,"left mouse button down :-(")

  CASE WM_LBUTTONUP
    SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)")
  END SELECT
END MDIEVENTS

which uses a procedure name, translates to

LRESULT CALLBACK ProcedureName(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  while(1)
  {
    if(Msg==WM_LBUTTONDOWN)
      {
        SetWindowText(Stat1,"left mouse button down :-(");
        break;
      }
    if(Msg==WM_LBUTTONUP)
      {
        SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)");
      }
    break;
  }
 return DefFrameProc(hWnd,BCX_hwndMDIClient,Msg,wParam,lParam);
}

This BCX code

BEGIN MDIEVENTS ProcedureName
  SELECT CASE CBMSG
  CASE WM_LBUTTONDOWN
    SetWindowText(Stat1,"left mouse button down :-(")

  CASE WM_LBUTTONUP
    SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)")
  END SELECT
END MDIEVENTS MAIN

which uses a procedure name and the MAIN statement appended to END MDIEVENTS, translates to

LRESULT CALLBACK ProcedureName(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  while(1)
  {
    if(Msg==WM_LBUTTONDOWN)
      {
        SetWindowText(Stat1,"left mouse button down :-(");
        break;
      }
    if(Msg==WM_LBUTTONUP)
      {
        SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)");
      }
    break;
  }
  if(Msg==WM_DESTROY)
    {
       PostQuitMessage(0);
       return 0;
    }
 return DefFrameProc(hWnd,BCX_hwndMDIClient,Msg,wParam,lParam);
}

This WM_DESTROY handler,

if(Msg==WM_DESTROY)
  {
   PostQuitMessage(0);
  }

is automatically generated by the BEGIN MDIEVENTS ... END MDIEVENTS statements when a ProcedureName is specified and the MAIN statement is appended to the END MDIEVENTS statement.

Therefore, in this instance, it is redundant to include

CASE WM_DESTROY
PostQuitMessage(0)

in the BCX code of the MDIEVENTS loop.


BCX_MDICLASS statement

Purpose:

The BCX_MDICLASS statement is valid only in BCX programs which use the MDIGUI statement. It creates a CLASS on which Multiple Document Interface (MDI) Child Windows can be based. This function should be placed in the SUB FORMLOAD ... END SUB section of the code. Every MDIGUI application needs at least one CLASS for child windows, and it is also possible to create multiple classes if required.

Syntax:

BCX_MDICLASS((WNDPROC)MdiChildWndProc, MdiChildWndClass AS STRING)

Parameters:

  • Data type: Identifier
    MdiChildWndProc Name of the callback function that the MDI windows of this class will use. The name should be cast to WNDPROC as shown.
  • Data type: STRING
    MdiChildWndClass User supplied name of the CLASS to create.

Remarks:

The BCX_MDICLASS statement does not return a value. See the example under BCX_MDICHILD function.


BCX_MDICLIENT function

Purpose:

The BCX_MDICLIENT function is valid only in BCX programs which use the MDIGUI statement. It creates a MDICLIENT window in which the Multiple Document Interface child windows can be displayed. This function should be placed in the SUB FORMLOAD ... END SUB section of the code. Every MDIGUI application needs a MDICLIENT area, and the application will not run if it is omitted.

Syntax:

hwndMDIClient = BCX_MDICLIENT(HndlWnd, Index)

Return Value:

  • Data type: HWND
    HndlWndMDIClient If the function succeeds, it will return a copy of the handle of the MDICLIENT window.

Parameters:

  • Data type: HWND
    HndlWnd Identifies the window on which the MDI CLIENT is placed.
  • Data type: INTEGER
    Index Index of the application menu to attach the list of open child windows.

BCX_MDICHILD function

Purpose:

The BCX_MDICHILD function is valid only in BCX programs which use the MDIGUI statement. It creates a MDICHILD window in the MDICLIENT area.

Syntax:

hwndMDIChild = BCX_MDICHILD(ChildTitle AS STRING, _
                      MdiChildWndClass AS STRING  _
                              [, Xpos AS INTEGER] _
                              [, Ypos AS INTEGER] _
                             [, Width AS INTEGER] _
                            [, Height AS INTEGER] _
                          [, MDIStyle AS INTEGER] _
                         [, MDILparam AS INTEGER])

Return Value:

  • Data type: HWND
    HndlWndMDIClient If the function succeeds, it will return a copy of the handle of the MDICLIENT window.

Parameters:

  • Data type: STRING
    ChildTitle Title of CHILD window created. If no title is given, the window will be given the name untitled.
  • Data type: STRING
    MdiChildWndClass The name of the class to base the child window on. This class must have been created with the BCX_MDICLASS function.
  • Data type: INTEGER
    Xpos [OPTIONAL] specifies the initial horizontal client coordinate of the MDICHILD window being created relative to the upper-left corner of the parent window's client area. The default argument for this parameter is CW_USEDEFAULT.
  • Data type: INTEGER
    Ypos [OPTIONAL] specifies the initial vertical client coordinate of the MDICHILD window being created relative to the upper-left corner of the parent window's client area. The default argument for this parameter is CW_USEDEFAULT.
  • Data type: INTEGER
    Width [OPTIONAL] specifies the width, in device units of the MDICHILD window being created. The default argument for this parameter is CW_USEDEFAULT.
  • Data type: INTEGER
    Height [OPTIONAL] specifies the height, in device units of the MDICHILD window being created. The default argument for this parameter is CW_USEDEFAULT.
  • Data type: INTEGER
    MDIStyle [OPTIONAL] If the MDIStyle% parameter is used, the default Window Style for a BCX_MDICHILD control, 0, is replaced with the value in MDIStyle%. For more information about valid MDIStyle values visit the Microsoft MDICREATESTRUCTA structure webpage..
  • Data type: INTEGER
    MDILparam [OPTIONAL] specifies a value defined by the application.

BEGIN MDICHILDEVENTS ... END MDICHILDEVENTS statements

Purpose:

In a MDIGUI multiple-document interface program code that is responsible for monitoring and responding to BCX_MDICHILD child window messages and commands like mouse clicks, button presses, radio controls and so on is placed between BEGIN MDICHILDEVENTS and END MDICHILDEVENTS.

Syntax:

BEGIN MDICHILDEVENTS ProcedureName
  ' Messages and Commands
END MDICHILDEVENTS

Parameters:

  • ProcedureName An unquoted name for the MDICHILDEVENTS loop.
    👉 The loop must be named.

Remarks:

Please note that the MAIN parameter, optionally used, appended to the END EVENTS or END MDIEVENTS loop terminators, cannot be used with the END MDICHILDEVENTS loop terminator.

This BCX code,

BEGIN MDICHILDEVENTS ProcedureName
  SELECT CASE CBMSG
  CASE WM_LBUTTONDOWN
    SetWindowText(Stat1,"left mouse button down :-(")

  CASE WM_LBUTTONUP
    SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)")
  END SELECT
END MDICHILDEVENTS

translates to

LRESULT CALLBACK ProcedureName(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  while(1)
  {
    if(Msg==WM_LBUTTONDOWN)
      {
        SetWindowText(Stat1,"left mouse button down :-(");
        break;
      }
    if(Msg==WM_LBUTTONUP)
      {
        SetWindowText(Stat1,"LEFT MOUSE BUTTON UP   :-)");
      }
    break;
  }
 return DefMDIChildProc(hWnd,Msg,wParam,lParam);
}

MDIGUI NOMAIN statement

Purpose:

The MDIGUI NOMAIN statement specifies that a WinMain function will not be automatically emitted. MDIGUI NOMAIN requires, at least, that the programmer provide a WinMain equivalent, register a ClassName and provide a message pump. The MDIGUI NOMAIN statement is similar to the $NOMAIN directive used in console mode programs.

Syntax:

MDIGUI NOMAIN [,PIXELS, ICON, ResInt]

Parameters:

  • Data type: Argument
    PIXELS [OPTIONAL] parameter indicating that pixels instead of dialog units are to be used in the placement and size arguments locating the control.
  • Data type: Argument
    ICON [OPTIONAL] parameter indicating that an icon is to be loaded as a resource.
  • Data type: INTEGER
    ResInt Used with ICON, specifies an integer value to an icon resource type defined in an .rc file or as a BCX_RESOURCE.

Remarks:

In a BCX MDIGUI NOMAIN program, all expressions must be inside a FUNCTION, SUB or the BEGIN MDIEVENTS procedure.


BCX_FRAMEWND function

Purpose:

BCX_FRAMEWND creates a MDI Frame Window along with an MDICLIENT Window. BCX_FRAMEWND returns the handle of the frame window and stores the MDICLIENT window handle in BCX_hwndMDIClient. The menu for the BCX_FRAMEWND must be loaded to an hMenu handle and included in the function parameters.

Syntax:

 HndlWnd = BCX_FRAMEWND(ClassName AS STRING, _
                   ProcedureName AS WNDPROC, _
                          Caption AS STRING  _
                          [, hmenu AS HMENU] _
                     [, hmenuPos AS INTEGER] _                        
                         [, Xpos AS INTEGER] _
                         [, Ypos AS INTEGER] _
                        [, Width AS INTEGER] _
                       [, Height AS INTEGER] _
                     [, WinStyle AS INTEGER] _
                   [, ExWinStyle AS INTEGER])

Return Value:

  • Data type: HWND
    HndlWnd The handle to a new window if the function succeeds. If the function fails, the return value is NULL.

Parameters:

  • Data type: STRING
    ClassName unique string literal name for the program. Every Windows MDIGUI program requires a ClassName. Windows uses the ClassName to distinguish one running program from another.
  • Data type: Identifier
    ProcedureName The unquoted name of this instance of a windows procedure. This name is used both for the WinProc procedure and for the BEGIN MDIEVENTS ... END MDIEVENTS loop.
  • Data type: STRING
    Caption [OPTIONAL] to be placed as title on the window.
  • hmenu [OPTIONAL] The handle of the menu containing the item that activates the MDICLIENT window. The default value of hMenu is NULL if the window uses the class menu.
  • Data type: INTEGER
    hmenuPos [OPTIONAL] zero-based ordinal position in the menu of the item that activates the MDICLIENT window. The default value of hMenuPos is 0.
  • Data type: INTEGER
    Xpos [OPTIONAL] specifies, in screen coordinates, the initial horizontal x-coordinate of the upper-left corner of the window being created. The default argument for this parameter is CW_USEDEFAULT. For more information, see the x parameter section of the Microsoft CreateWindowExA function webpage.
  • Data type: INTEGER
    Ypos [OPTIONAL] specifies, in screen coordinates, the initial vertical y-coordinate of the upper-left corner of the window being created. The default argument for this parameter is CW_USEDEFAULT. For more information, see the y parameter section of the Microsoft CreateWindowExA function webpage.
  • Data type: INTEGER
    Width [OPTIONAL] specifies, in PIXELS, the width of the window being created. The default argument for this parameter is CW_USEDEFAULT. For more information, see the nWidth parameter section of the Microsoft CreateWindowExA function webpage.
  • Data type: INTEGER
    Height [OPTIONAL] specifies, in PIXELS, the height of the window being created. The default argument for this parameter is CW_USEDEFAULT. For more information, see the nHeight parameter section of the Microsoft CreateWindowExA function webpage.
  • Data type: INTEGER
    WinStyle [OPTIONAL] If the WinStyle parameter is used, the default Window Style for a BCX_FRAMEWND control, 0, is replaced with the value in WinStyle. For more information, visit the Microsoft Window Styles webpage
  • Data type: INTEGER
    ExWinStyle [OPTIONAL] The default Extended Window Style for a BCX_FRAMEWND is 0. For more information, visit the Microsoft Extended Window Styles webpage.

Example:

The following is a BCX_FRAMEWND program. Save the example code below as bcx_framewnd.bas.

Save the following batch file, as Build.bat, into the same directory as bcx_framewnd.bas and run Build.bat to compile and run the example.

Build.bat Compilation Batch file:

CALL povars64.bat
bc bcx_framewnd

bcx_framewnd.bas

MDIGUI NOMAIN, PIXELS, ICON, 123

$IPRINT_OFF

$COMPILER "$PELLES$\Bin\pocc /W1 /Ot /MT /Go /Gd /Ze /Zx _
                   /Tx64-coff -D__STDC_WANT_LIB_EXT2__=1 _
                  /D_WIN32_WINNT=0x502 /std:c17 $FILE$.c"
 
$LINKER "$PELLES$\Bin\polink _
                    -release _
                -machine:X64 _
     -SUBSYSTEM:WINDOWS,5.02 _
             -OUT:$FILE$.exe _
                  $FILE$.obj _
                $FILE$__.res"

$RESOURCE "$PELLES$\bin\porc.exe"

$BCX_RESOURCE

 #define IDM_NEW          10
 #define IDM_OPEN         20
 #define IDM_SAVE         30
 #define IDM_SAVEAS       40
 #define IDM_PRINT        50
 #define IDM_CLOSE        70
 #define IDM_EXIT         60

 #define IDM_WORDWRAP    300
 #define IDM_FONT        310

 #define IDM_UNDO        100
 #define IDM_CUT         110
 #define IDM_COPY        120
 #define IDM_PASTE       130
 #define IDM_DEL         140
 #define IDM_SELALL      150

 #define IDM_CASCADE     160
 #define IDM_TILE        170
 #define IDM_ARRANGE     180
 #define IDM_CLOSEALL    190

 #define IDM_HELP        200
 #define IDM_ABOUT       210

 #define CBWNDEXTRA       12

 #define GWL_HWNDEDIT      0
 #define GWL_EDITCHANGED   4
 #define ID_EDIT         300
 #define IDM_FIRSTCHILD  400
 #define ID_MAINMENU     500

 ID_MAINMENU MENU DISCARDABLE

 BEGIN
   POPUP "&File"
     BEGIN
       MENUITEM "&New",           IDM_NEW
       MENUITEM "&Open...",       IDM_OPEN
       MENUITEM "&Save",          IDM_SAVE
       MENUITEM "Save &As...",    IDM_SAVEAS
       MENUITEM "&Close",         IDM_CLOSE
       MENUITEM SEPARATOR
       MENUITEM "&Print",         IDM_PRINT
       MENUITEM SEPARATOR
       MENUITEM "E&xit",          IDM_EXIT
     END
   POPUP "&Edit"
     BEGIN
       MENUITEM "&Undo",          IDM_UNDO
       MENUITEM SEPARATOR
       MENUITEM "Cu&t",           IDM_CUT
       MENUITEM "&Copy",          IDM_COPY
       MENUITEM "&Paste",         IDM_PASTE
       MENUITEM "De&lete",        IDM_DEL
       MENUITEM SEPARATOR
       MENUITEM "&Select All",    IDM_SELALL
     END
   POPUP "F&ormat"
     BEGIN
       MENUITEM "&Wordwrap",      IDM_WORDWRAP
       MENUITEM "&Font",          IDM_FONT
     END
   POPUP "&Window"
     BEGIN
       MENUITEM "&Cascade",       IDM_CASCADE
       MENUITEM "&Tile",          IDM_TILE
       MENUITEM "Arrange &Icons", IDM_ARRANGE
       MENUITEM "Close &All",     IDM_CLOSEALL
     END
   POPUP "&Help"
     BEGIN
       MENUITEM "&Help...",       IDM_HELP
       MENUITEM "&About...",      IDM_ABOUT
     END
 END

$BCX_RESOURCE

DIM Form1 AS HWND        ' Main window handle

'----------------------------------------------------------

MACRO IDM_NEW         = 10
MACRO IDM_OPEN        = 20
MACRO IDM_SAVE        = 30
MACRO IDM_SAVEAS      = 40
MACRO IDM_PRINT       = 50
MACRO IDM_CLOSE       = 70
MACRO IDM_EXIT        = 60

MACRO IDM_UNDO        = 100
MACRO IDM_CUT         = 110
MACRO IDM_COPY        = 120
MACRO IDM_PASTE       = 130
MACRO IDM_DEL         = 140
MACRO IDM_SELALL      = 150

MACRO IDM_WORDWRAP    = 300
MACRO IDM_FONT        = 310

MACRO IDM_CASCADE     = 160
MACRO IDM_TILE        = 170
MACRO IDM_ARRANGE     = 180
MACRO IDM_CLOSEALL    = 190

MACRO IDM_HELP        = 200
MACRO IDM_ABOUT       = 210

MACRO CBWNDEXTRA      = 12

MACRO GWL_HWNDEDIT    = 0
MACRO GWL_EDITCHANGED = 4
MACRO ID_EDIT         = 300
MACRO IDM_FIRSTCHILD  = 400
MACRO ID_MAINMENU     = 500

'----------------------------------------------------------

FUNCTION WINMAIN ()
 RAW hMenu AS HMENU
 'Attach the main menu
 hMenu = LoadMenu(BCX_HINSTANCE , MAKEINTRESOURCE(ID_MAINMENU))
 Form1 = BCX_FRAMEWND( "MAINFORM", FrameWndProc, "Mini-Multi-Pad", hMenu, 4, 0, 0, 1080, 760)
 ' BCX_MDICLASS takes the name of the callback function
 ' and the name of the class
 BCX_MDICLASS((WNDPROC) MDIChildWndProc, "MdiChildWndClass")
 BCX_MDICHILD("", "MdiChildWndClass", 0, 0, 600, 480, WS_MAXIMIZE)

 CENTER(Form1)
 SHOW(Form1)
 SendMessage(BCX_hwndMDIClient, WM_MDICASCADE, 0, 0)

 FUNCTION = BCX_MDI_MSGPUMP()
END FUNCTION

'----------------------------------------------------------

BEGIN MDIEVENTS FrameWndProc
  HANDLE_CMD( IDM_NEW, newChild,0)
  HANDLE_CMD( IDM_OPEN, openChild,0)
  HANDLE_CMD( IDM_SAVE, saveChild,0)
  HANDLE_CMD( IDM_SAVEAS, saveAsChild,0)
  HANDLE_CMD( IDM_FONT, fontChild)
  HANDLE_CMD( IDM_CASCADE, mdiCascade)
  HANDLE_CMD( IDM_TILE, mdiTile)
  HANDLE_CMD( IDM_ARRANGE, mdiArrange)
  HANDLE_CMD( IDM_CLOSEALL, mdiCloseAll)
  HANDLE_CMD( IDM_CLOSE, mdiClose)
  HANDLE_CMD( IDM_ABOUT, mdiAbout)
  HANDLE_CMD( IDM_EXIT, mdiExit)
  HANDLE_MSG( WM_QUERYENDSESSION, mdiEndSession,0)
  HANDLE_MSG( WM_CLOSE, mdiEndSession,0)
END MDIEVENTS MAIN

CMDHANDLER saveChild
 DIM FileName$
 DIM Mask$
 Mask$ = "All Files(*.*)|*.*|"
 DIM RetVal%
 RAW hwndChild AS HWND
 RAW hEdit AS HWND
 RAW length
 RAW buffer$ * 10
 hwndChild =(HWND)SendMessage(BCX_hwndMDIClient, WM_MDIGETACTIVE, 0, 0)
 hEdit =(HWND) GetWindowLongPtr(hwndChild, GWL_HWNDEDIT)
 length = GetWindowTextLength(hEdit)
 REDIM buffer$ * length
 GetWindowText(hEdit, buffer$, length + 1)
 FileName$ = GETFILENAME$("Save", Mask$, 1) ' set flag to use SAVE Dialog 
 IF FileName$ = "" THEN
  MSGBOX "File Save Cancelled"
 ELSE
  IF EXIST(FileName$) = TRUE THEN
   RetVal% = MSGBOX("Overwrite " & FileName$ & "?","Confirm File Overwrite",MB_YESNO+MB_ICONEXCLAMATION)
   IF RetVal% = IDNO THEN
    GOTO jmp1
   ELSE
    OPEN FileName$ FOR OUTPUT AS FP1
    FPRINT FP1, buffer$
    CLOSE FP1
    SendMessage(hwndChild, WM_SETTEXT, 0, FileName$)
    GOTO jmp1
   END IF
  ELSE
    OPEN FileName$ FOR OUTPUT AS FP1
    FPRINT FP1, buffer$
    CLOSE FP1
    SendMessage(hwndChild, WM_SETTEXT, 0, FileName$)
  END IF
 END IF
jmp1:
END HANDLER
 
CMDHANDLER saveAsChild
 DIM FileName$
 DIM Mask$
 Mask$ = "All Files(*.*)|*.*|"
 DIM RetVal%
 RAW hwndChild AS HWND
 RAW hEdit AS HWND
 RAW length
 RAW buffer$ * 10
 hwndChild =(HWND)SendMessage(BCX_hwndMDIClient, WM_MDIGETACTIVE, 0, 0)
 hEdit =(HWND) GetWindowLongPtr(hwndChild, GWL_HWNDEDIT)
 length = GetWindowTextLength(hEdit)
 REDIM buffer$ * length
 GetWindowText(hEdit, buffer$, length + 1)
 FileName$ = GETFILENAME$("Save As", Mask$, 1) ' set flag to use SAVE Dialog 
 IF FileName$ = "" THEN
  MSGBOX "File Save Cancelled"
 ELSE
  IF EXIST(FileName$) = TRUE THEN
   RetVal% = MSGBOX("Overwrite " & FileName$ & "?","Confirm File Overwrite",MB_YESNO+MB_ICONEXCLAMATION)
   IF RetVal% = IDNO THEN
    GOTO jmp2
   ELSE
    OPEN FileName$ FOR OUTPUT AS FP1
    FPRINT FP1, buffer$
    CLOSE FP1
    SendMessage(hwndChild, WM_SETTEXT, 0, FileName$)
    GOTO jmp2
   END IF
  ELSE
    OPEN FileName$ FOR OUTPUT AS FP1
    FPRINT FP1, buffer$
    CLOSE FP1
    SendMessage(hwndChild, WM_SETTEXT, 0, FileName$)
  END IF
 END IF
jmp2:
END HANDLER

MSGHANDLER mdiEndSession
  SendMessage(hWnd,WM_COMMAND,IDM_CLOSEALL,0)
  DestroyWindow( Form1)
END HANDLER

CMDHANDLER mdiCascade
  SendMessage(BCX_hwndMDIClient, WM_MDICASCADE, 0, 0)
END HANDLER

CMDHANDLER mdiTile
  SendMessage(BCX_hwndMDIClient, WM_MDITILE, 0, 0)
END HANDLER

CMDHANDLER mdiArrange
  SendMessage(BCX_hwndMDIClient, WM_MDIICONARRANGE, 0, 0)
END HANDLER

CMDHANDLER mdiCloseAll
  EnumChildWindows(BCX_hwndMDIClient,CloseEnumProc,0)
END HANDLER

CMDHANDLER mdiClose
  SendMessage((HWND)SendMessage( BCX_hwndMDIClient, WM_MDIGETACTIVE, 0, 0), WM_CLOSE, 0, 0)
END HANDLER

CMDHANDLER mdiExit
  SendMessage( Form1, WM_CLOSE, 0, 0)
END HANDLER

CMDHANDLER mdiAbout
  MessageBox(hWnd, "Mini-Multi-Pad Editor" + CR$ + _
  "     Vic McClung", "About", 0)
END HANDLER
 
CMDHANDLER newChild()
  BCX_MDICHILD("", "MdiChildWndClass", 0, 0, 640, 480, WS_MAXIMIZE)
END HANDLER

CMDHANDLER openChild
  RAW hChildWnd AS HWND
  RAW filename$
  RAW hEdit AS HWND
  RAW buffer$ * 10
  filename$ = GETFILENAME$("Open a Text File", "*.txt", 0, hWnd)
  IF filename$ <> "" THEN
    REDIM buffer$ * LOF(filename$)
    buffer$ = LOADFILE$(filename$)
    hChildWnd = BCX_MDICHILD("", "MdiChildWndClass", 0, 0, 640, 480, WS_MAXIMIZE)
    hEdit =(HWND) GetWindowLongPtr(hChildWnd, GWL_HWNDEDIT)
    EDITLOADFILE(hEdit, filename$)
    SendMessage( hChildWnd, WM_SETTEXT, 0, filename$)
  END IF
END HANDLER

CMDHANDLER fontChild
  RAW hwndChild AS HWND
  RAW hEdit AS HWND
  hwndChild =(HWND)SendMessage( BCX_hwndMDIClient, WM_MDIGETACTIVE, 0, 0)
  hEdit =(HWND) GetWindowLongPtr(hwndChild, GWL_HWNDEDIT)
  IF BCX_FONTDLG(TRUE, hEdit) THEN
    BCX_SET_FONT(hEdit, BCX_Font.Name$, BCX_Font.Size, _
    BCX_Font.Bold, BCX_Font.Italic, BCX_Font.Underline, _
    BCX_Font.Strikeout)
  END IF
END HANDLER

'----------------------------------------------------------

BEGIN MDICHILDEVENTS MDIChildWndProc
  HANDLE_MSG(WM_CREATE,  child_OnCreate)
  HANDLE_MSG(WM_SIZE,    child_OnSize)
  HANDLE_CMD( ID_EDIT, edit_OnCommand, 0)
  HANDLE_MSG WM_SETFOCUS INLINE "SetFocus((HWND)GetWindowLongPtr(hWnd, GWL_HWNDEDIT))"
  HANDLE_MSG WM_CLOSE INLINE "SendMessage(GetParent(hWnd),WM_MDIDESTROY,hWnd,0)"
END MDICHILDEVENTS


MSGHANDLER child_OnCreate
  RAW hwndEdit AS HWND
  RAW Style = WS_CHILD | WS_HSCROLL | WS_VISIBLE | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE
  hwndEdit = BCX_RICHEDIT("", hWnd, ID_EDIT, 0, 0, 0, 0, Style)
 ' Remember the edit control's window handle,
 ' and set the edit changed flag to 0.
 ' You can use this to see if you can close
 ' the child window.
  SetWindowLongPtr(hWnd, GWL_HWNDEDIT,(LONG)hwndEdit);
  SetWindowLongPtr(hWnd, GWL_EDITCHANGED, 0);
  SetFocus(hwndEdit);
END HANDLER

MSGHANDLER child_OnSize
  RAW hwndEdit AS HWND
  'Move the edit control to MDI child's size.
  hwndEdit =(HWND)GetWindowLongPtr(hWnd, GWL_HWNDEDIT)
  IF NOT MoveWindow(hwndEdit, 0, 0, LOWORD(lParam),HIWORD(lParam), TRUE) THEN
   MessageBox(NULL,"Could not move window", NULL, 0)
  END IF
END HANDLER

MSGHANDLER edit_OnCommand
  RAW hwndEdit AS HWND
  hwndEdit =(HWND)GetWindowLongPtr(hWnd, GWL_HWNDEDIT)
  IF lParam AND LOWORD(wParam) = ID_EDIT THEN
    SELECT CASE HIWORD(wParam)
      CASE EN_UPDATE, EN_CHANGE
      SetWindowLongPtr(hWnd, GWL_EDITCHANGED, 1)
      EXIT FUNCTION
    END SELECT
    EXIT FUNCTION
  END IF
END HANDLER

'----------------------------------------------------------

FUNCTION CloseEnumProc (hWnd AS HWND,lParam AS LPARAM) AS BOOL CALLBACK
  ' Check for icon title
  IF (GetWindow(hWnd,GW_OWNER)) THEN
    FUNCTION = TRUE
  END IF
  SendMessage(GetParent(hWnd),WM_MDIRESTORE,(WPARAM) hWnd,0)
  IF NOT SendMessage(hWnd,WM_QUERYENDSESSION,0,0) THEN
    FUNCTION = TRUE
  END IF
  SendMessage(GetParent(hWnd),WM_MDIDESTROY,hWnd,0)
  FUNCTION = TRUE
END FUNCTION

'----------------------------------------------------------