Win32Forth


Multiple Document Interface (MDI) classes


MDI.f contains classes that form the basis for writing MDI aplications (like MS Word and MS Excel).  Each document in an MDI application is displayed in a separate child window within the client area of the application's main window.

MDI client control class

:Class MDIClientWindow   <super Control

MDI client control class. This control is used by the MDIFrameWindow class. You shouldn't create instances of this class within your application.

:M Start: ( hWindowMenu Parent -- )

Start the control.

:M CreateStruct: ( -- CreateStrucPointer )

Get the address of CLIENTCREATESTRUCT structure. It contains information about the menu and first multiple document interface (MDI) child window of an MDI client window. An application passes a pointer to this structure as the lpvParam parameter of the CreateWindow function when creating an MDI client window.

;Class

End of MDIClientWindow class

MDI Frame window class

:Class MDIFrameWindow   <super Window

All MDI child windows are displayed within the client area of this window.

:M WindowMenuNo: ( -- n )

Override this method to set the menu number in whitch all child windows should be displayed.

:M WindowTitle: ( -- z" )

Get the title text for the frame window.

:M SetRedraw:   ( f -- )

Set the redraw state of the window.

 f  Specifies the redraw state. If this parameter is TRUE, the content can be redrawn after a change. If this parameter is FALSE, the content cannot be redrawn after a change.

:M Tile:        ( f -- )

Arrange all child windows in a tile format.

 f  can be one of the following values optionally combined with MDITILE_SKIPDISABLED to prevent disabled MDI child windows from being tiled.

MDITILE_HORIZONTAL Tiles windows horizontally.
MDITILE_VERTICAL Tiles windows vertically.
:M Arrange:     ( -- )

Arrange all minimized child windows. It does not affect child windows that are not minimized.

:M Cascade:     ( -- )

Arrange all child windows in a cascade format.

:M RefreshMenu: ( -- )

Refresh the window menu of the MDI frame window.

:M MDISetMenu:  ( hmenuWindow hmenuFrame -- )

Replace the entire menu of an MDI frame window, replace the window menu

of the frame window, or both.

:M DrawMenuBar: ( -- )

Redraws the menu bar of the window. If the menu bar changes after the system has created the window, this function must be called to draw the changed menu bar.

:M Restore:     ( hWnd -- )

Restore an MDI child window from maximized or minimized size.

:M Maximize:    ( hWnd -- )

M maximize an MDI child window. The system resizes the child window to make its client area fill the client window. The system places the child window's window menu icon in the rightmost position of the frame window's menu bar, and places the child window's restore icon in the leftmost position. The system also appends the title bar text of the child window to that of the frame window.

:M GetActive:   ( -- Maximized handle )

Retrieve the handle to the active MDI child window.

:M Activate:    ( hWnd -- )

Activate a MDI child window.

:M Next:        ( f hWnd -- )

Activate the next or previous child window.

:M Destroy:     ( hWnd -- )

Destroy an MDI child window.

:M CloseChild:  ( hWnd -- )

Close an MDI child window.

:M EnumChildWindows: ( lparam pCallBack -- f )

Enumerate the MDI child windows

:M CloseAll:    ( -- )

Close all MDI child windows.

:M GetFirstChild: ( -- hWndChild )

Get handle of the first child window

:M GetNextChild: ( -- hWndChild )

Get handle of the next child window.       
NOTE: you must call GetFirstChild: first.

:M SendMessageToAllChildren: { wParam lParam msg -- }

Send a message to all child windows

:M PostMessageToAllChildren: { wParam lParam msg -- }

Post a message to all child windows

;Class

End of MDIFrameWindow class

MDI Child window class

:Class MDIChildWindow   <super child-window

This is the base class for all windows that should be displayed within the client area of a MDIFrameWindow.

:M DefaultIcon: ( -- hIcon )

Return the handle of the Icon whitch should be displayed in the upper left corner of the MDi child window.

:M ParentWindow: ( -- hParent )

Teturn the handle of parent, 0 = no parent

:M Start: ( Parent -- )

Create a new MDI child window object

:M WindowTitle: ( -- z" )

Get the title text for the MDI child window.

:M On_QueryEnd: ( -- f )

This method is called when the user chooses to end the session or when an application calls the ExitWindows function. If any application returns zero, the session is not ended.

The default method returns TRUE, so that the session will be ended.

:M On_Close: ( -- f )

This method is called when the user chooses to close the MDI child window. If it returns FALSE the window will not be closed.

Override the method to check if the document within the child window need's to be saved.

The default method returns TRUE, so that the window will be closed.

:M On_ChildActivate: ( -- )

Handle the WM_CHILDACTIVATE message. This message is sent to a child window when the user clicks the window's title bar or when the window is activated, moved, or sized.

:M On_GetMinMaxInfo: ( pMinMaxInfo -- pMinMaxInfo )

Handle the WM_GETMINMAXINFO message. This message is sent to a window when the size or position of the window is about to change. An application can use this message to override the window's default maximized size and position, or its default minimum or maximum tracking size.

 pMinMaxInfo  Pointer to a MINMAXINFO structure that contains the default maximized position and dimensions, and the default minimum and maximum tracking sizes. An application can override the defaults by setting the members of this structure.

:M On_MenuChar: ( w l -- w l )

Handle the WM_MENUCHAR message. This message is sent when a menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key. This message is sent to the window that owns the menu.

:M On_Move: ( l -- l )

Handle the WM_MOVE message. This message is sent after a window has been moved.

:M On_SysCommand: ( h m w l -- h m w l f )

Handle the WM_SYSCOMMAND message. A window receives this message when the user chooses a command from the window menu or when the user chooses the maximize button, minimize button, restore button, or close button.

:M On_Command: ( h m w l -- h m w l f )

Handle the WM_COMMAND message. This message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

;Class

End of MDIChildWindow class

Example (demos\MdiExample.f)

Needs MDI

0 value CurrentWindow
0 value ActiveChild
Create CurrentFile 256 allot


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Messages and Dialogs
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

: ?SaveMessage ( -- n )   \ IDYES, IDNO or IDCANCEL
        s" Do you want to save " pad place
        CurrentFile count "to-pathend" pad +place
        s"  ?" pad +place  pad +NULL
        pad 1+ z" MDI Example"
        [ MB_ICONEXCLAMATION  MB_YESNOCANCEL or ] literal
        NULL MessageBox ;


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Simple TextBox to place on child windows
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

:Class TextBox   <Super Control

:M Start: ( Parent -- )
        to Parent
        z" EDIT" Create-Control
        ;M

:M WindowStyle: ( -- style )
        [ WS_VISIBLE WS_CHILD or ES_MULTILINE or WS_VSCROLL or WS_HSCROLL or ] literal
        ;M

;Class


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Define application menu
\
\ The frame window of an MDI application should include
\ a menu bar with a Window menu. The Window menu should
\ include command items that arrange the child windows
\ within the client window or that close all child windows.
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

200 value (NewID)
: NewID ( <name> -- )   defined
        IF  drop
        ELSE  count "header  (NewID)  dup 1+ to (NewID)  DOCON , ,
        THEN ;

NewID IDM_NEW
NewID IDM_CLOSE
NewID IDM_EXIT
NewID IDM_TILE
NewID IDM_ARRANGE
NewID IDM_CASCADE
NewID IDM_CLOSE_ALL
NewID IDM_OPEN_FILE

Create MenuTable (NewID) 200 - 4 * allot
: DoMenu ( ID -- )   200 - 4 * MenuTable + @ ?dup IF execute THEN ;
: SetMenu ( ID -- )  last @ name>  swap 200 - 4 * MenuTable + ! ;

MENUBAR MDIMenu
    POPUP "&File"
        MENUITEM     "&New...   \tCtrl+N"     IDM_NEW               DoMenu ;
        MENUITEM     "C&lose"                 IDM_CLOSE             DoMenu ;
\     9 RECENTFILES   RecentFiles             IDM_OPEN_FILE         DoMenu ;
        MENUSEPARATOR
        MENUITEM     "E&xit  \tAlt-F4"        IDM_EXIT              DoMenu ;
    POPUP "&Window"
        MENUITEM     "&Tile"                  IDM_TILE              DoMenu ;
        MENUITEM     "&Arrange"               IDM_ARRANGE           DoMenu ;
        MENUITEM     "Ca&scade"               IDM_CASCADE           DoMenu ;
        MENUITEM     "&Close all"             IDM_CLOSE_ALL         DoMenu ;
ENDBAR


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Define application window
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

:Object Frame   <Super MDIFrameWindow

:M Classinit: ( -- )
        ClassInit: super
        MDIMenu to CurrentMenu
        ;M

:M WindowMenuNo: ( -- n )   1 ;M   \ the Window menu where the child window titles will be placed

:M WindowStyle: ( -- style )
        WindowStyle: SUPER
        WS_CLIPCHILDREN or
        ;M

:M ExWindowStyle: ( -- exstyle )
        WS_EX_ACCEPTFILES
        ;M

:M WM_DROPFILES { hndl message wParam lParam \ drop$ -- res }
        SetForegroundWindow: self
        MAXSTRING LocalAlloc: drop$
        0 0 -1 wParam Call DragQueryFile
        0 DO
            MAXCOUNTED drop$ 1+ i wParam Call DragQueryFile drop$ c!
            drop$ IDM_OPEN_FILE DoMenu
        LOOP
        wParam Call DragFinish
        ;M

:M MinSize: ( -- width height )   106  0  ;M

:M WindowTitle: ( -- z" )   z" MDI Example"  ;M

:M On_Size: ( h m w -- )
        0 0 Width Height Move: MDIClient
        ;M
(( This is equivalent to  :M WM_SIZE  ( h m w l -- f )   DefFrameProc ;M
   but if space for a Toolbar or StatusBar is needed MDIClient needs to be smaller ))

:M On_Init: ( -- )
        On_Init: super
        100 appinst Call LoadIcon   \ Win32For.ico
        GCL_HICON hWnd Call SetClassLong drop
        ;M

:M OnWmCommand:  ( hwnd msg wparam lparam -- hwnd msg wparam lparam )
        OnWmCommand: Super
        over LOWORD ( Menu ID )  dup 200 (NewID) within   \ intercept Menu commands
        IF  DoMenu  ELSE  drop  THEN
        ;M

:M WM_CLOSE ( h m w l -- res )
        CloseAll: self
        NotCancelled                    \ if we don't cancel the close
        IF
            WM_CLOSE WM: super          \ then just terminate the program
        ELSE
            1                           \ else abort program termination
        THEN
        ;M

:M On_Done: ( -- )
        Turnkeyed? IF  0 call PostQuitMessage drop  THEN
        On_Done: Super
        ;M

;Object


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Define Child Window class
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

:Class MDIChild   <Super MDIChildWindow
    int EditWindow
    256 bytes FileName
    int Modified

:M WindowTitle: ( -- z" )
        CurrentFile count FileName place
        FileName +null  FileName 1+
        ;M

:M WindowStyle: ( -- style )
        WindowStyle: super
        WS_CLIPCHILDREN or
        GetActive: Frame  0= or  IF  WS_MAXIMIZE or  THEN   \ start new child maximised unless
        ;M                                                  \ the active child is not maximised

:M DefaultIcon: ( -- hIcon )
        101 appInst Call LoadIcon   \ App_icon.ico
        ;M

:M Start: ( parent -- )
        New> TextBox to EditWindow
        Start: super
        self start: EditWindow
        0 0 Width Height Move: EditWindow
        SetFocus: EditWindow
        True to Modified
        ;M

:M On_SetFocus: ( -- )              \ A child window can be selected by clicking on it,
        SetFocus: EditWindow        \ selecting it from the Window menu or using CTRL+F6
        EditWindow to CurrentWindow
        self to ActiveChild
        FileName count CurrentFile place CurrentFile +null
        ;M

:M On_Size: ( h m w l -- h m w l )
        0 0 Width Height Move: EditWindow   \ make TextBox fit child window
        ;M

:M On_Close: ( -- f )   \ True = close, False = cancel close
        Modified
        IF
            ?SaveMessage
            Case
                IDCANCEL  Of                 FALSE  Endof
                IDYES     Of                  TRUE  Endof
                ( otherwise IDNO )            TRUE  swap
            EndCase
        ELSE  TRUE
        THEN
        dup  dup to NotCancelled
        IF                                   \ if we don't cancel the close
            GetHandle: self Destroy: Frame   \ close child window first
            EditWindow dispose               \ so we can safely dispose
            self dispose                     \ of both the EditControl
        THEN                                 \ and the child window
        ;M

;Class


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Activate Menu
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

0 value New#
: New ( -- )   1 +to New#  s" File " currentfile place
        New# (.) currentfile +place
        New> MDIChild to ActiveChild
        MDIClientWindow: Frame Start: ActiveChild ;             IDM_NEW SetMenu
: Close ( -- )   GetHandle: ActiveChild CloseChild: Frame ;   IDM_CLOSE SetMenu
: ExitApp ( -- )   bye ;                                       IDM_EXIT SetMenu
: Tile ( -- )   0 Tile: Frame ;                                IDM_TILE SetMenu
: Arrange ( -- )   Arrange: Frame ;                         IDM_ARRANGE SetMenu
: Cascade ( -- )   Cascade: Frame ;                         IDM_CASCADE SetMenu
: CloseAll ( -- )   CloseAll: Frame ;                     IDM_CLOSE_ALL SetMenu
: OpenFile ( File$ -- )   count currentfile place
        New> MDIChild to ActiveChild
        ( File opening stuff )
        MDIClientWindow: Frame Start: ActiveChild ;       IDM_OPEN_FILE SetMenu

******* many menu items not implemented here **********

\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       Handle MDI Accelerators: ALT+ - (minus), CTRL+ F4, CTRL+ F6
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

: DoMDIMsg ( pMsg f  -- pMsg f )
        dup MDIClient: Frame 0<> and
        IF
            drop dup MDIClient: Frame Call TranslateMDISysAccel 0=
        THEN
        ;
msg-chain chain-add DoMDIMsg


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\       The word to start the application
\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

: go   ( -- )
       zeromenu: mdimenu
       start: Frame
       0 to New#
       New
       Cascade
       Turnkeyed? IF  Begin key drop again  THEN
       ;


Document $Id: mdi.htm,v 1.10 2007/05/26 10:24:13 dbu_de Exp $