/*
 * Xailer source code:
 *
 * Form.prg
 * Clase TForm()
 *
 * Copyright 2003, 2007 Jose F. Gimenez
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"


//--------------------------------------------------------------------------

CLASS XForm FROM TScrollingWinControl

PUBLISHED:
   PROPERTY nLeft    INIT CW_USEDEFAULT
   PROPERTY nTop     INIT CW_USEDEFAULT
   PROPERTY nWidth   INIT CW_USEDEFAULT
   PROPERTY nHeight  INIT CW_USEDEFAULT

   PROPERTY nClientWidth
   PROPERTY nClientHeight

   PROPERTY lParentIcon INIT .T. WRITE INLINE ::SetIcon( Nil, Value )

   PROPERTY oIcon       READ METHOD GetIcon  WRITE METHOD SetIcon EDITOR PE_Icon AS TIcon

   PROPERTY lAppWindow   INIT .F.
   PROPERTY lModal       INIT .F.
   PROPERTY lCentered    INIT .F. WRITE INLINE ::FlCentered := Value, ;
                                        IIf( Value .AND. ! Empty( ::Handle ), IIf( ::nFormType == ftMDICHILD, CenterMDIWindow( ::Handle ), CenterWindow( ::Handle ) ), )
   PROPERTY nShowMode    INIT SW_NORMAL VALUES smNORMAL, smMAXIMIZE, smMINIMIZE

   PROPERTY nBorderStyle DEFAULT bsSIZEABLE WRITE METHOD SetBorderStyle ;
                         VALUES bsNONE, bsSINGLE, bsSIZEABLE, bsDIALOG, bsTOOLWINDOW, bsSIZETOOLWIN, bsSPLASH

   PROPERTY nFormType    INIT ftNORMAL VALUES ftNORMAL, ftMDIFRAME, ftMDICHILD
   PROPERTY lSysMenu     INIT .T.
   PROPERTY lCloseBox    INIT .T.
   PROPERTY lMinimizeBox INIT .T.
   PROPERTY lMaximizeBox INIT .T.
   PROPERTY lHelpIcon    INIT .F.

   PROPERTY lHideOnClose      INIT .F.
   PROPERTY lDirectShortCuts  INIT .F.

   PROPERTY nMinWidth   INIT 0 WRITE METHOD SetMinSize
   PROPERTY nMinHeight  INIT 0 WRITE INLINE ::SetMinSize( ,Value )
   PROPERTY nMaxWidth   INIT 0 WRITE METHOD SetMaxSize
   PROPERTY nMaxHeight  INIT 0 WRITE INLINE ::SetMaxSize( ,Value )
   PROPERTY nMaxPosX    INIT 0 WRITE METHOD SetMaxPos
   PROPERTY nMaxPosY    INIT 0 WRITE INLINE ::SetMaxPos( ,Value )

   PROPERTY lMsgAuto    INIT .F.

   PROPERTY XHtmlHelp   INIT ""  EDITOR PE_XHtmlHelp

   EVENT OnCreate( oSender ) // --> Nil
   EVENT OnInitialize( oSender ) // --> Nil
   EVENT OnClose( oSender, @lClose ) // --> lResult
   EVENT OnActivate( oSender, oCtl ) // --> Nil
   EVENT OnDeactivate( oSender, oCtl ) // --> Nil
   EVENT OnSize( oSender, nSizeType, nClientWidth, nClientHeight ) // --> Nil
   EVENT OnMove( oSender, nLeft, nTop ) // --> Nil
   EVENT OnChangeFocus( oSender, oPrevCtl, oNextCtl ) // --> Nil
   EVENT OnMenuSelect( oSender, nFlags, hMenu, cMessage, oMenuItem ) // --> Nil
   EVENT OnHelp( oSender, HelpId, nPosX, nPosY ) // --> Nil
   EVENT OnHelpClick( oSender ) // --> Nil | Zero
   EVENT OnCopyData( oSender, cString, nMsgId ) // --> lResult
   EVENT OnHotKey( oSender, nId, nKey ) // --> Nil

PROTECTED:
   DATA nCtlStyle    INIT nOr( WS_OVERLAPPEDWINDOW, WS_CLIPCHILDREN, WS_HSCROLL, WS_VSCROLL )
   DATA nExStyle     INIT WS_EX_CONTROLPARENT
   DATA nClassStyle  INIT nOr( CS_HREDRAW, CS_VREDRAW )

   DATA aShortCut    INIT {}
   DATA nLastID      INIT 100

   PROPERTY nAlign
   PROPERTY nAlignMarginLeft
   PROPERTY nAlignMarginTop
   PROPERTY nAlignMarginRight
   PROPERTY nAlignMarginBottom
   PROPERTY nAnchors
   PROPERTY lParentFont
   PROPERTY l3D         INIT .F.
   PROPERTY lBorder     INIT .F.
   PROPERTY lTabStop    INIT .F.
   PROPERTY cMessage

   EVENT OnEnter
   EVENT OnExit

PUBLIC:
   PROPERTY lVisible       INIT .F.
   PROPERTY oActiveControl WRITE INLINE ::FoActiveControl := Value AS TControl
   PROPERTY oMDIMenu       WRITE METHOD SetMDIMenu AS TMenu

   DATA     aComponents    INIT {}
   DATA     oMsgBar

   PROPERTY lActive  INIT .F. READONLY

   DATA nModalResult INIT 0  // For ShowModal() return value
   DATA oMdiClient   READONLY AS TMdiClient

   METHOD New( oParent ) CONSTRUCTOR
   METHOD Create( oParent ) CONSTRUCTOR

   METHOD Show( nCmdShow, lCenter ) // --> Nil
   METHOD ShowModal( nCmdShow ) EXTERN FormShowModal( nCmdShow ) // --> nResult
   METHOD Close( lDontAsk ) INLINE ::SendMsg( WM_CLOSE, lDontAsk, 0 ), ( ::Handle == 0 .OR. ! ::lVisible ) // --> Nil

   METHOD Enable() // --> .T.
   METHOD Disable() // --> .F.

   METHOD Restore()  INLINE ShowWindow( ::Handle, SW_RESTORE ) // --> lSuccess
   METHOD Maximize() INLINE ShowWindow( ::Handle, SW_MAXIMIZE ) // --> lSuccess
   METHOD Minimize() INLINE ShowWindow( ::Handle, SW_MINIMIZE ) // --> lSuccess
   METHOD SetFocus() // --> .F.
   METHOD SaveState() // --> cString
   METHOD RestoreState( cState, lSetPositionOnly ) // --> cString

   METHOD SetRoundCorners( lRoundCorners ) // --> Nil    NOTE: Only Windows 11

RESERVED:
   DATA oPrevWnd
   DATA oPopup          AS TPopupMenu
   DATA oDefaultButton  AS TButton
   DATA oCancelButton   AS TButton

   PROPERTY cBalloon
   PROPERTY cTooltip
   PROPERTY cTooltipTitle
   PROPERTY nTooltipIcon

   METHOD Scale( nScale )
   METHOD CreateMDIClient()
   METHOD CreateForm() VIRTUAL
   METHOD Free()
   METHOD SetBorderStyle( nBorderStyle )
   METHOD SetIcon( oIcon, lParentIcon )
   METHOD GetIcon()
   METHOD GetFont()
   METHOD SetMinSize( nMinWidth, nMinHeight )
   METHOD SetMaxSize( nMaxWidth, nMaxHeight )
   METHOD SetMaxPos( x, y )
   METHOD InsertComponent( oComponent )
   METHOD RemoveComponent( oComponent )
   METHOD SetMDIMenu( oSubMenu )
   METHOD GetNewID() INLINE ::nLastID++
   METHOD AddShortCut( oControl )
   METHOD DelShortCut( oControl )
   METHOD Help( oSender, HelpId, nPosX, nPosY )
   METHOD Gesture() VIRTUAL

   METHOD WMKeyDown( nKey, nFlags, hWnd )
   METHOD WMKeyUp( nKey, nFlags )   INLINE ::OnKeyUp( nKey, nFlags )
   METHOD WMChar( nKey, nFlags )
   METHOD WMSysKeyDown( nKey, nFlags ) INLINE ::SendMsg( WM_CHANGEUISTATE, MakeLong( UIS_CLEAR, UISF_HIDEFOCUS + UISF_HIDEACCEL ) ), Nil
   METHOD WMSysKeyUp( nKey, nFlags ) VIRTUAL
   METHOD WMSysChar( nKey, nFlags )
   METHOD WMClose( nWParam, nLParam )
   METHOD WMCreate()
   METHOD WMNCDestroy()
   METHOD WMSize( nWParam, nLParam )
   METHOD WMShowWindow( wParam, lParam )
   METHOD WMNCPaint()      VIRTUAL
   METHOD WMNCCalcSize()   VIRTUAL
   METHOD WMMove( nWParam, nLParam ) INLINE ::OnMove( LoWord( nLParam ), HiWord( nLParam ) )
   METHOD WMGetMinMaxInfo()
   METHOD WMSetFocus()
   METHOD WMNCActivate()
   METHOD WMActivate( nWParam, nLParam )
   METHOD WMInitMenu( nWParam, nLParam ) INLINE IIf( ::oMenu != Nil .AND. ::oMenu:Handle == nWParam, ::oMenu:RequestState(), )
   METHOD WMMenuSelect( nFlags, hMenu )
   METHOD WMChildActivate()
   METHOD WMWindowPosChanging()
   METHOD WMCommand( wParam, Handle )
   METHOD WMSysCommand( nWParam, nLParam )
   METHOD WMDrawItem()
   METHOD WMMeasureItem()

   METHOD WMDisplayChange() INLINE Screen:GetValues(), Nil
   METHOD WMCopyData( nWParam, nLParam )

   METHOD WMHotKey( nWParam, nLParam ) INLINE ::OnHotKey( nWParam, nLParam )

   METHOD WMHelp( nWParam, nLParam )

PROTECTED:
   DATA hItemID

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oParent ) CLASS XForm

   IF oParent != Nil .AND. !oParent:IsKindOf( "XForm" ) .AND. oParent:IsKindOf( "XControl" )
      oParent := oParent:oForm
   ENDIF
   ::Super:New( oParent )
   ::CreateForm( .T. )
   ::OnInitialize()
   ::CreateMDIClient()

RETURN Self

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XForm

   LOCAL hParent, hSysMenu, n
   LOCAL nClientWidth, nClientHeight

   IF ! ::lCreated

      UPDATE ::oParent   TO oParent
      DEFAULT ::oParent  TO GetControlFromHandle( GetActiveWindow() )
      DEFAULT ::oParent  TO Application
      DEFAULT ::oBrush   TO TBrush():Create( Nil, ::nClrPane )

      ::oForm := Self

      IF ::lModal .AND. ::nFormType == ftMDICHILD
         ::nFormType := ftNORMAL
      ENDIF

      ::SetBorderStyle()
      IF ! ::lSysMenu
         ::nCtlStyle := nExclude( ::nCtlStyle, WS_SYSMENU )
      ENDIF
      IF ! ::lMinimizeBox
         ::nCtlStyle := nExclude( ::nCtlStyle, WS_MINIMIZEBOX )
      ENDIF
      IF ! ::lMaximizeBox
         ::nCtlStyle := nExclude( ::nCtlStyle, WS_MAXIMIZEBOX )
      ENDIF
      IF ::lHelpIcon
         ::nExStyle := nOr( ::nExStyle, WS_EX_CONTEXTHELP )
      ENDIF
      IF ::nFormType == ftMDICHILD
         ::nExStyle := nOr( ::nExStyle, WS_EX_MDICHILD )
      ELSEIF Application:oMainForm == Nil .OR. ::lAppWindow
         ::nExStyle := nOr( ::nExStyle, WS_EX_APPWINDOW )
      ENDIF

      ::Register()
      ::OnBeforeCreate()
      ::Link( ::nFormType == ftMDICHILD )
      IF ::oParent != Nil .AND. !( ::oParent == Application )
         IF ::nFormType == ftMDICHILD .AND. ::oParent:IsKindOf( "XForm" ) .AND. ::oParent:oMdiClient != Nil
            ::oMdiClient := ::oParent:oMdiClient
            hParent := ::oParent:oMdiClient:Handle
         ELSE
            hParent := ::oParent:Handle
         ENDIF
      ELSE
         hParent := 0
      ENDIF
      ::Scale( Application:nScale )
      nClientWidth := ::nClientWidth
      nClientHeight := ::nClientHeight
      IF ( ::Handle := CreateWindow( ::ClassName, ::cText, ::nCtlStyle, ::nExStyle, ;
                                     ::nLeft, ::nTop, ::nWidth, ::nHeight, hParent ) ) != 0
         ::lCreated := .T.
         IF ::oParent != Nil .AND. lAnd( ::nCtlStyle, WS_CHILD )
            ::oParent:InsertControl( Self )
         ENDIF
         ::SetFont()
         ::UpdateBounds()
         IF nClientWidth > 0
            ::SetClientSize( nClientWidth )
         ENDIF
         IF nClientHeight > 0
            ::SetClientSize( , nClientHeight )
         ENDIF
         If ! Empty( ::oIcon )
            ::SendMsg( WM_SETICON, ICON_BIG, ::oIcon:Handle )
         ENDIF
         IF ! ::lCloseBox
            hSysMenu := GetSystemMenu( ::Handle )
            FOR n := 0 TO GetMenuItemCount( hSysMenu )
               IF GetMenuItemID( hSysMenu, n ) == SC_CLOSE
                  DeleteMenu( hSysMenu, n, MF_BYPOSITION )
                  IF GetMenuItemID( hSysMenu, n - 1 ) == 0 .OR. GetMenuItemID( hSysMenu, n - 1 ) == SC_SEPARATOR
                     DeleteMenu( hSysMenu, n - 1, MF_BYPOSITION )
                  ENDIF
                  EXIT
               ENDIF
            NEXT
         ENDIF
      ENDIF
      Application:InsertForm( Self )
      IF ::nFormType == ftMDICHILD .AND. ::oMdiClient != Nil
         ::oMdiClient:InsertForm( Self )
      ENDIF
      IF ::lDragAcceptFiles
         DragAcceptFiles( ::Handle, .T. )
      ENDIF
      ::OnCreate()

   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Scale( nScale ) CLASS XForm

   DEFAULT nScale TO Application:nScale

   IF nScale != 100
      ::FnLeft          := MulDiv( ::FnLeft, nScale, 100 )
      ::FnTop           := MulDiv( ::FnTop, nScale, 100 )
      ::FnWidth         := MulDiv( ::FnWidth, nScale, 100 )
      ::FnHeight        := MulDiv( ::FnHeight, nScale, 100 )
      ::FnClientWidth   := MulDiv( ::FnClientWidth, nScale, 100 )
      ::FnClientHeight  := MulDiv( ::FnClientHeight, nScale, 100 )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD CreateMDIClient() CLASS XForm

   IF ::nFormType == ftMDIFRAME .AND. ::oMdiClient == Nil
      ::oMdiClient := TMDIClient():Create( Self )
      IF ::FoMDIMenu != Nil
         ::oMdiClient:SendMsg( WM_MDISETMENU,, ::FoMDIMenu:Handle )
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD Free() CLASS XForm

   LOCAL nFor

   // NOTA: Impedir que se vuelva a disparar este evento durante la destruccion del formulario - [JFG]
   ::OnSize := Nil

	FOR nFor := Len( ::aComponents ) TO 1 Step -1
		IF nFor <= Len( ::aComponents )
	      ::aComponents[ nFor ]:End()
		ENDIF
   NEXT

   ::oActiveControl := Nil

   IF ! ::lParentIcon .AND. ::oIcon != Nil
      ::oIcon:Destroy()
   ENDIF

RETURN ::Super:Free()

//--------------------------------------------------------------------------

METHOD SetBorderStyle( nBorderStyle ) CLASS XForm

   STATIC aFormClasses := { "TFormNone", "TFormSingle", "TForm", "TDialog", "TToolWindow", "TSizeToolWin", "TSplash" }

   UPDATE ::FnBorderStyle TO nBorderStyle

   IF ::FnBorderStyle != bsCUSTOM
      ::nCtlStyle := nOr( WS_CAPTION, WS_CLIPSIBLINGS, WS_CLIPCHILDREN, WS_SYSMENU )
      ::nExStyle := 0
      IF AScan( aFormClasses, ::ClassName ) > 0
         ::ClassName := Nil
      ENDIF
   ENDIF

   IF ::FnBorderStyle == bsNONE
      ::nCtlStyle := nOr( WS_POPUP, WS_CLIPSIBLINGS, WS_CLIPCHILDREN )
      DEFAULT ::ClassName TO "TFormNone"

   ELSEIF ::FnBorderStyle == bsSINGLE
      ::nCtlStyle := nOr( ::nCtlStyle, WS_OVERLAPPED )
      DEFAULT ::ClassName TO "TFormSingle"

   ELSEIF ::FnBorderStyle == bsSIZEABLE
      ::nCtlStyle := nOr( ::nCtlStyle, WS_OVERLAPPED, WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX )
      DEFAULT ::ClassName TO "TForm"

   ELSEIF ::FnBorderStyle == bsDIALOG
      ::nCtlStyle := nOr( WS_BORDER, WS_SYSMENU, WS_CLIPSIBLINGS, WS_CLIPCHILDREN, WS_DLGFRAME )
      ::nExStyle := nOr( WS_EX_DLGMODALFRAME, WS_EX_WINDOWEDGE) //, WS_EX_CONTEXTHELP )
      ::nClassStyle := CS_SAVEBITS
      DEFAULT ::ClassName TO "TDialog"

   ELSEIF ::FnBorderStyle == bsTOOLWINDOW
      ::nCtlStyle := nOr( ::nCtlStyle, WS_OVERLAPPED )
      ::nExStyle := nOr( ::nExStyle, WS_EX_TOOLWINDOW )
      DEFAULT ::ClassName TO "TToolWindow"

   ELSEIF ::FnBorderStyle == bsSIZETOOLWIN
      ::nCtlStyle := nOr( ::nCtlStyle, WS_OVERLAPPED, WS_THICKFRAME )
      ::nExStyle := nOr( ::nExStyle, WS_EX_TOOLWINDOW )
      DEFAULT ::ClassName TO "TSizeToolWin"

   ELSEIF ::FnBorderStyle == bsSPLASH
      ::nCtlStyle := nOr( WS_POPUP, WS_CLIPCHILDREN, WS_DLGFRAME )
      ::nExStyle := WS_EX_TOPMOST
      IF Application:nWinVer > 5  // WinXP & >
         #define CS_DROPSHADOW       0x00020000
         ::nClassStyle := CS_DROPSHADOW
      ENDIF
      DEFAULT ::ClassName TO "TSplash"
   ENDIF

RETURN ::FnBorderStyle

//--------------------------------------------------------------------------

METHOD SetIcon( oIcon, lParentIcon ) CLASS XForm

   LOCAL hIcon := 0

   UPDATE ::FlParentIcon TO lParentIcon

   IF ::FoIcon != Nil
      ::FoIcon:Destroy()
   ENDIF

   IF oIcon != Nil
      IF ValType( oIcon ) != "O"
         oIcon := TIcon():Create( oIcon )
      ENDIF
      ::FoIcon := oIcon
      ::FlParentIcon := .F.
      hIcon := ::FoIcon:Handle
   ELSE
      ::FoIcon := Nil
      IF ::FlParentIcon .AND. ::oParent != Nil
         IF ::oParent:GetIcon() != Nil
            hIcon := ::oParent:GetIcon():Handle
         ENDIF
      ENDIF
   ENDIF

   IF ! Empty( ::Handle )
      ::SendMsg( WM_SETICON, ICON_BIG, hIcon, 0 )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD GetIcon() CLASS XForm

   IF ::FlParentIcon .AND. ::oParent != Nil .AND. __ObjHasMsg( ::oParent, "GetIcon" )
      RETURN ::oParent:GetIcon()
   ENDIF

RETURN ::FoIcon

//--------------------------------------------------------------------------

METHOD GetFont() CLASS XForm

   IF ::FoFont == Nil
      ::FoFont := Application:oFont:Clone()
   ENDIF

RETURN ::FoFont

//--------------------------------------------------------------------------

METHOD Show( nCmdShow, lCenter ) CLASS XForm

   DEFAULT nCmdShow TO ::nShowMode
   DEFAULT lCenter  TO ::lCentered

   IF Empty( ::Handle )
      ::Create()
   ENDIF

   IF lCenter .AND. ! IsWindowVisible( ::Handle )
      IF ::nFormType == ftMDICHILD
         CenterMDIWindow( ::Handle )
      ELSE
         CenterWindow( ::Handle )
      ENDIF
   ENDIF
   ::Super:Show( nCmdShow )
   ::UpdateBounds()
   IF ::nFormType == ftMDICHILD
      IF ! Empty( ::oParent:oMdiClient )
         ::oParent:oMdiClient:SendMsg( WM_MDIACTIVATE, ::Handle )
      ENDIF
   ELSE
      ::CreateMDIClient()
      IF !Empty( ::oActiveControl )
         ::oActiveControl:GotFocus()
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD Enable() CLASS XForm
RETURN ::TControl:Enable()

//--------------------------------------------------------------------------

METHOD Disable() CLASS XForm
RETURN ::TControl:Disable()

//--------------------------------------------------------------------------

METHOD SetMinSize( nMinWidth, nMinHeight ) CLASS XForm

   UPDATE ::FnMinWidth  TO nMinWidth
   UPDATE ::FnMinHeight TO nMinHeight

RETURN { ::FnMinWidth, ::FnMinHeight }

//--------------------------------------------------------------------------

METHOD SetMaxSize( nMaxWidth, nMaxHeight ) CLASS XForm

   UPDATE ::FnMaxWidth  TO nMaxWidth
   UPDATE ::FnMaxHeight TO nMaxHeight

RETURN { ::FnMaxWidth, ::FnMaxHeight }

//--------------------------------------------------------------------------

METHOD SetMaxPos( x, y ) CLASS XForm

   UPDATE ::FnMaxPosX TO x
   UPDATE ::FnMaxPosY TO y

RETURN { ::FnMaxPosX, ::FnMaxPosY }

//--------------------------------------------------------------------------

METHOD InsertComponent( oComponent ) CLASS XForm

   IF AScan( ::aComponents, {| o | o == oComponent } ) == 0
      AAdd( ::aComponents, oComponent )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD RemoveComponent( oComponent ) CLASS XForm

   LOCAL n

   IF ( n := AScan( ::aComponents, {| oComp | oComp == oComponent } ) ) > 0
      ADel( ::aComponents, n )
      ASize( ::aComponents, Len( ::aComponents ) - 1 )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD AddShortCut( oControl, aKeys ) CLASS XForm

   LOCAL nAt

   IF aKeys == Nil
      IF ! Empty( oControl:GetText() ) .AND. ( nAt := At( "&", oControl:GetText() ) ) > 0
         AAdd( ::aShortCut, { oControl, Upper( Substr( oControl:GetText(), nAt + 1, 1 ) ), .F. } )
      ENDIF
   ELSE
      AEval( aKeys, {| cKey | AAdd( ::aShortCut, { oControl, Upper( cKey ), .T. } ) } )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD DelShortCut( oControl ) CLASS XForm

   LOCAL nAt := AScan( ::aShortCut, {| aShortCut | oControl == aShortCut[ 1 ] } )

   WHILE nAt > 0
      ADel( ::aShortCut, nAt )
      ASize( ::aShortCut, Len( ::aShortCut ) - 1 )
      IF Len( ::aShortCut ) < nAt .OR. !( ::aShortCut[ nAt, 1 ] == oControl )
         nAt := 0
      ENDIF
   ENDDO

RETURN Nil

//--------------------------------------------------------------------------

METHOD SetMDIMenu( oSubMenu ) CLASS XForm

   LOCAL hMenu, hMenuWnd

   UPDATE ::FoMDIMenu TO oSubMenu

   IF ::oMenu != Nil
      hMenu := ::oMenu:Handle
   ENDIF
   IF ::oMdiMenu != Nil
      hMenuWnd := ::oMdiMenu:Handle
   ENDIF
   IF ::oMdiClient != Nil
      ::oMdiClient:SendMsg( WM_MDISETMENU, hMenu, hMenuWnd )
      ::oMdiClient:SendMsg( WM_MDIREFRESHMENU )
   ENDIF
   DrawMenuBar( ::Handle )

RETURN ::FoMDIMenu

//--------------------------------------------------------------------------

METHOD WMKeyDown( nKey, nFlags ) CLASS XForm

   LOCAL uRet, lOk

   IF ( uRet := ::OnKeyDown( nKey, nFlags ) ) != Nil
      RETURN uRet
   ENDIF

   IF nKey == VK_RETURN
      IF ::oDefaultButton != Nil .AND. IsWindowEnabled( ::oDefaultButton:Handle ) .AND. IsWindowVisible( ::oDefaultButton:Handle )
         IF ::oActiveControl == Nil .OR. ( lOk := ::oActiveControl:Valid( ::oDefaultButton ) ) == Nil .OR. lOk
            ::oDefaultButton:Click()
         ENDIF
         RETURN 0
      ELSEIF Application:lUseReturn
         ::GoNextControl()
         RETURN 0
      ENDIF
   ELSEIF nKey == VK_ESCAPE
      IF ::oCancelButton != Nil .AND. IsWindowEnabled( ::oCancelButton:Handle ) .AND. IsWindowVisible( ::oCancelButton:Handle )
         ::oCancelButton:Click()
         RETURN 0
      ELSEIF ::nBorderStyle == bsDIALOG .AND. ::lCloseBox
         ::Close()
         RETURN 0
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMChar( nKey, nFlags ) CLASS XForm

   LOCAL uRet

   IF ( uRet := ::OnChar( nKey, nFlags ) ) != Nil
      RETURN uRet
   ENDIF

   IF nKey == VK_RETURN .OR. nKey == VK_ESCAPE
      RETURN 0
   ENDIF

   IF ::lDirectShortCuts
      RETURN ::WMSysChar( nKey, nFlags )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMSysChar( nKey, nFlags ) CLASS XForm

   LOCAL nAt := 0, cKey := Upper( Chr( nKey ) )

   DO WHILE ( nAt := AScan( ::aShortCut, {| aShortCut | cKey == aShortCut[ 2 ] }, nAt + 1 ) ) > 0
      IF IsWindowEnabled( ::aShortCut[ nAt, 1 ]:Handle ) .AND. IsWindowVisible( ::aShortCut[ nAt, 1 ]:Handle )
         RETURN ::aShortCut[ nAt, 1 ]:ShortCut( IIf( ::aShortCut[ nAt, 3 ], cKey, Nil ) )
      ENDIF
   ENDDO

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMClose( nWParam, nLParam ) CLASS XForm

   LOCAL lClose := .T., lRet, oMdiChild

   IF nWParam == 0
      IF Valtype( lRet := ::OnClose( @lClose ) ) == "L" .AND. ! lRet .OR. ! lClose
         RETURN 0
      ENDIF
      // NOTA: Validar tambien las MDIChild - [JFG]
      IF ::nFormType == ftMDIFRAME .AND. !Empty( ::oMdiClient )
         FOR EACH oMdiChild IN ::oMdiClient:aForms
            IF Valtype( lRet := oMdiChild:OnClose( @lClose ) ) == "L" .AND. ! lRet .OR. ! lClose
               RETURN 0
            ENDIF
         NEXT
      ENDIF
   ENDIF

   IF nLParam == 0
      IF ! Empty( ::oPrevWnd ) .AND. ::oPrevWnd:Handle != 0
         ::oPrevWnd:Enable()
         ::oPrevWnd:SetFocus()
         ::oPrevWnd := Nil
      ELSEIF ::oParent:IsKindOf( "XForm" )
         ::oParent:Enable()
      ENDIF
   ENDIF

   IF ::lHideOnClose
      ::Hide()
      RETURN 0
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMNCDestroy() CLASS XForm

   ::Super:WMNCDestroy()
   Application:RemoveForm( Self )
   IF ::nFormType == ftMDICHILD .AND. ::oMdiClient != Nil
      ::oMdiClient:RemoveForm( Self )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMSize( nWParam, nLParam ) CLASS XForm

   LOCAL uRet

   ::Super:WMSize( nWParam, nLParam )

   IF ::oMsgBar != Nil
      ::oMsgBar:Resize()
   ENDIF

   IF ( nWParam == 0 .AND. nLParam == 0 ) .OR. ( nWParam == -1 .AND. ::nFormType == ftMDICHILD )
      RETURN 0
   ENDIF
   IF ( uRet := ::OnSize( nWParam, LoWord( nLParam ), HiWord( nLParam ) ) ) == Nil .AND. ::nFormType != ftMDICHILD
      uRet := 0
   ENDIF

RETURN uRet

//--------------------------------------------------------------------------

METHOD WMShowWindow( nWParam, nLParam ) CLASS XForm

   IF nWParam != 0 .AND. nLParam == 0
      ::AlignControls()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD SetFocus() CLASS XForm

   LOCAL hNext

   IF ::lVisible
      IF ::nFormType == ftMDICHILD .AND. ::oParent:oMdiClient != Nil
         IF Len( ::oParent:oMdiClient:aForms ) < 2
            ::oParent:oMdiClient:SendMsg( WM_MDIACTIVATE, ::Handle )
         ELSE
            hNext := GetWindow( ::Handle, GW_HWNDNEXT )
            ::oParent:oMdiClient:SendMsg( WM_MDINEXT, hNext, .T. )
         ENDIF
      ELSE
         SetFocus( ::Handle )
      ENDIF
   ENDIF

RETURN .F.

//--------------------------------------------------------------------------

METHOD WMSetFocus( nWParam, nLParam ) CLASS XForm

   LOCAL hMdiChild

   IF ::nFormType == ftMDIFRAME .AND. ::oMdiClient != Nil
      IF ( hMdiChild := ::oMdiClient:SendMsg( WM_MDIGETACTIVE ) ) != 0
         // NOTA: Dejar los 2 mensajes; hay partes que necesitan el mensaje
         //       inmediatamente y otras partes que lo necesitan al final - [JFG]
         IF ::Handle == nWParam
            PostMessage( hMdiChild, WM_CHILDACTIVATE )
         ELSE
            SendMessage( hMdiChild, WM_CHILDACTIVATE )
         ENDIF
         RETURN 0
      ENDIF
   ENDIF

RETURN ::Super:WMSetFocus( nWParam, nLParam )

//--------------------------------------------------------------------------

METHOD WMNCActivate( nWParam, nLParam ) CLASS XForm

   IF ::nFormType == ftMDICHILD
      IF nWParam == 0
         RETURN ::OnDeactivate()
      ELSE
         ::oParent:oMdiClient:SetActiveForm( Self )
         ::Update()
         RETURN ::OnActivate()
      ENDIF
   ELSE
      ::Update()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMActivate( nWParam, nLParam ) CLASS XForm

   LOCAL oForm := GetControlFromHandle( nLParam )

   IF LoWord( nWParam ) != 0
      // Activate
      ::lActive := .T.
      IF ::oPrevWnd == Nil .AND. oForm != Nil .AND. oForm:IsKindOf( "XForm" )
         ::oPrevWnd := oForm
      ENDIF
      Application:SetActiveForm( Self )
      RETURN ::OnActivate( oForm )
   ENDIF
   // Deactivate
   ::lActive := .F.

RETURN ::OnDeactivate( oForm )

//--------------------------------------------------------------------------

METHOD WMMenuSelect( wParam, hMenu ) CLASS XForm

   STATIC cTextSimple
   STATIC lStatusSimple

   LOCAL nID, nFlags, n
   LOCAL oItem, oMenu
   LOCAL cMessage

   nID    := LOWORD( wParam )
   nFlags := HIWORD( wParam )

   IF hMenu != 0

      IF ::oMenu != Nil
         oItem := ::oMenu:FindItem( nID, hMenu )
      ENDIF

      IF oItem == Nil .AND. ::oPopup != Nil
         oItem := ::oPopup:FindItem( nID, hMenu )
      ENDIF

      IF oItem == Nil .AND. ::nFormType == ftMDIFRAME .AND. ::oMdiClient != Nil
         IF ::oMdiClient:oActiveForm != Nil .AND. ( oMenu := ::oMdiClient:oActiveForm:oMenu ) != Nil
            oItem := oMenu:FindItem( nID )
         ENDIF
      ENDIF

      IF oItem != Nil
         cMessage := oItem:cMessage
      ENDIF

      IF ::EventAssigned( "OnMenuSelect" )
         ::OnMenuSelect( wParam, hMenu, cMessage, oItem  )
      ELSE
         IF ::oMsgBar != Nil
            IF lStatusSimple == Nil
               lStatusSimple     := ::oMsgBar:lSimple
               ::oMsgBar:lSimple := .T.
               cTextSimple       := ::oMsgBar:cText
            ENDIF
            ::oMsgBar:cText   := cMessage
         ENDIF
      ENDIF
   ELSE
      IF ::EventAssigned( "OnMenuSelect" )
         ::OnMenuSelect( wParam, hMenu, Nil )
      ELSEIF ::oMsgBar != Nil .AND. lStatusSimple != Nil
         ::oMsgBar:cText   := cTextSimple
         ::oMsgBar:lSimple := lStatusSimple
         lStatusSimple     := Nil
      ENDIF
   ENDIF

RETURN 0

//--------------------------------------------------------------------------

METHOD WMWindowPosChanging() CLASS XForm

   IF ::nFormType == ftMDICHILD
      ::oParent:oMdiClient:SendMsg( WM_NCPAINT )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMChildActivate() CLASS XForm

   LOCAL hMenu, hMenuWnd

   IF ::oMenu != Nil
      hMenu := ::oMenu:Handle
   ELSEIF ::oParent:oMenu != Nil
      hMenu := ::oParent:oMenu:Handle
   ENDIF
   IF ::oMdiMenu != Nil
      hMenuWnd := ::oMdiMenu:Handle
   ELSEIF ::oParent:oMdiMenu != Nil
      hMenuWnd := ::oParent:oMdiMenu:Handle
   ENDIF
   ::oParent:oMdiClient:SendMsg( WM_MDIREFRESHMENU )
   ::oParent:oMdiClient:SendMsg( WM_MDISETMENU, hMenu, hMenuWnd )
   DrawMenuBar( ::oParent:Handle )

   IF Empty( ::oActiveControl )
      ::oActiveControl := ::GoFirstControl()
   ELSE
      ::oActiveControl:SetFocus()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMCommand( wParam, Handle ) CLASS XForm

   LOCAL nNotifyCode := HiWord( wParam )
   LOCAL nId := LoWord( wParam )
   LOCAL lOk := .F.

   IF Handle == 0 .AND. nNotifyCode == 0  // Menu
      IF ::lPopup .AND. ! Empty( ::oForm:oPopup )
         lOk := ::oForm:oPopup:DoAction( nId )
      ELSEIF ::nFormType == ftMDIFRAME .AND. ( ::oMenu == Nil .OR. ::oMenu:Handle != GetMenu( ::Handle ) )
         IF ::oMdiClient:oActiveForm:oMenu != Nil
            lOk := ::oMdiClient:oActiveForm:oMenu:DoAction( nId )
         ENDIF
      ELSEIF ! Empty( ::oMenu )
         lOk := ::oMenu:DoAction( nId )
      ENDIF
      IF lOk
         RETURN 0
      ENDIF
   ENDIF

RETURN ::Super:WMCommand( wParam, Handle )

//--------------------------------------------------------------------------

METHOD WMSysCommand( nWParam, nLParam ) CLASS XForm

   IF nWParam == SC_CONTEXTHELP
      RETURN ::OnHelpClick()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD RestoreState( cState, lSetPositionOnly ) CLASS XForm

   LOCAL x, y, cx, cy

   DEFAULT lSetPositionOnly TO .F.

   IF cState != Nil .AND. Len( cState ) == 17
      x := Bin2i( I2bin( HexToDec( Substr( cState, 1, 4 ) ) ) )
      y := Bin2i( I2bin( HexToDec( Substr( cState, 5, 4 ) ) ) )
      cx := Bin2i( I2bin( HexToDec( Substr( cState, 9, 4 ) ) ) )
      cy := Bin2i( I2bin( HexToDec( Substr( cState, 13, 4 ) ) ) )
      ::SetBounds( x, y, cx, cy )
      IF ! Empty( ::Handle )
         IF ! lSetPositionOnly
            cState := Substr( cState, 17, 1 )
            IF IsUpper( cState )
               IF cState == "X"
                  ::Maximize()
               ELSEIF cState == "M"
                  ::Minimize()
               ELSE
                  ::Restore()
                  IF ::nLeft != x .OR. ::nTop != y .OR. ::nWidth != cx .OR. ::nHeight != cy
                     ::SetBounds( x, y, cx, cy )
                  ENDIF
               ENDIF
            ELSE
               ::Hide()
            ENDIF
         ENDIF
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMHelp( nWParam, nLParam ) CLASS XForm

   IF !Empty( ::XHtmlHelp )
      IF ::EventAssigned( "OnHelp" )
         ::OnHelp( ::XHtmlHelp, 0, 0 )
      ELSE
          Application:Help( Self, ::XHtmlHelp, 0, 0 )
      ENDIF
      RETURN 0
   ENDIF

RETURN ::Super:WMHelp( nWParam, nLParam )

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#include <windows.h>
#include <xailer.h>
#include <constants.ch>

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_WMCREATE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = (HWND) hb_parnl( 3 );

   if ( ( hWnd ) && ( XA_ObjGetNL( Self, "FnBorderStyle" ) == bsDIALOG ) )
      {
      HMENU SysMenu = GetSystemMenu( hWnd, FALSE );
      DeleteMenu( SysMenu, SC_TASKLIST, MF_BYCOMMAND );
      DeleteMenu( SysMenu, 7, MF_BYPOSITION );
      DeleteMenu( SysMenu, 5, MF_BYPOSITION );
      DeleteMenu( SysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
      DeleteMenu( SysMenu, SC_MINIMIZE, MF_BYCOMMAND );
      DeleteMenu( SysMenu, SC_SIZE, MF_BYCOMMAND );
      DeleteMenu( SysMenu, SC_RESTORE, MF_BYCOMMAND );
      }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_WMGETMINMAXINFO )
{
   PHB_ITEM Self = hb_stackSelfItem();
   LPMINMAXINFO mmi = (LPMINMAXINFO) hb_parnl( 2 );
   UINT nMinWidth  = XA_ObjGetNL( Self, "FnMinWidth" );
   UINT nMinHeight = XA_ObjGetNL( Self, "FnMinHeight" );
   UINT nMaxWidth  = XA_ObjGetNL( Self, "FnMaxWidth" );
   UINT nMaxHeight = XA_ObjGetNL( Self, "FnMaxHeight" );
   UINT nMaxPosX   = XA_ObjGetNL( Self, "FnMaxPosX" );
   UINT nMaxPosY   = XA_ObjGetNL( Self, "FnMaxPosY" );

   if ( ( nMinWidth > 0 ) || ( nMinHeight > 0 ) )
      {
      mmi->ptMinTrackSize.x = nMinWidth;
      mmi->ptMinTrackSize.y = nMinHeight;
      }
   if ( ( nMaxWidth > 0 ) || ( nMaxHeight > 0 ) )
      {
      mmi->ptMaxTrackSize.x = nMaxWidth;
      mmi->ptMaxTrackSize.y = nMaxHeight;
      }
   if ( ( nMaxPosX > 0 ) || ( nMaxPosY > 0 ) )
      {
      mmi->ptMaxPosition.x = nMaxPosX;
      mmi->ptMaxPosition.y = nMaxPosY;
      }

   hb_ret();
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_SAVESTATE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   char *cState = hb_xgrab( 18 ), *pState = cState;
   WINDOWPLACEMENT wp;

   wp.length = sizeof( WINDOWPLACEMENT );
   if( GetWindowPlacement( hWnd, &wp ) )
      {
      strcpy( pState, W2Hex( wp.rcNormalPosition.left ) ); pState += 4;
      strcpy( pState, W2Hex( wp.rcNormalPosition.top ) ); pState += 4;
      strcpy( pState, W2Hex( wp.rcNormalPosition.right - wp.rcNormalPosition.left ) ); pState += 4;
      strcpy( pState, W2Hex( wp.rcNormalPosition.bottom - wp.rcNormalPosition.top ) ); pState += 4;
      switch( wp.showCmd )
         {
         case SW_SHOWMINIMIZED:
            *pState = 'M'; break;
         case SW_SHOWMAXIMIZED:
            *pState = 'X'; break;
         default:
            *pState = 'N';
         }
      if( !IsWindowVisible( hWnd ) )
         *pState += 0x20;
      *(++pState) = 0;
      }
   else
      *pState = 0;

   hb_retc( cState );
   hb_xfree( cState );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_WMDRAWITEM )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   PHB_ITEM oControl;
   LPDRAWITEMSTRUCT di = (LPVOID) hb_parnl( 2 );

   hb_ret();

   if ( di->CtlType == ODT_MENU )
      {
      PHB_ITEM oItem = hb_itemNew( NULL );
      PHB_ITEM oPopup = XA_ObjGetItemCopy( Self, "oPopup" );
      PHB_ITEM oMenu = XA_ObjGetItemCopy( Self, "oMenu" );

      if ( !HB_IS_NIL( oMenu ) )
         {
         XA_ObjSendNL( oMenu, "FindItem", di->itemID );
         if ( HB_ISNIL( -1 ) && !HB_IS_NIL( oPopup ) )
            XA_ObjSendNL( oPopup, "FindItem", di->itemID );
         }
      else
         if ( !HB_IS_NIL( oPopup ) )
            XA_ObjSendNL( oPopup, "FindItem", di->itemID );

      if ( !HB_ISNIL( -1 ) )
         {
         hb_itemCopy( oItem, hb_param( -1, HB_IT_OBJECT ) );
         if ( oItem )
            XA_ObjSendNL( oItem, "DrawItem", (long) di );
         }

      hb_itemRelease( oItem );
      hb_itemRelease( oPopup );
      hb_itemRelease( oMenu );
      }
   else
      {
      oControl = GetControlFromHandle( GetDlgItem( hWnd, di->CtlID ) );
      if ( oControl )
         XA_ObjSendNL( oControl, "DrawItem", hb_parnl( 2 ) );
      }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_WMMEASUREITEM )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   PHB_ITEM oControl;
   LPMEASUREITEMSTRUCT mi = (LPVOID) hb_parnl( 2 );

   hb_ret();

   if ( mi->CtlType == ODT_MENU )
      {
      PHB_ITEM oItem = hb_itemNew( NULL );
      PHB_ITEM oPopup = XA_ObjGetItemCopy( Self, "oPopup" );
      PHB_ITEM oMenu = XA_ObjGetItemCopy( Self, "oMenu" );

      if ( !HB_IS_NIL( oMenu ) )
         {
         XA_ObjSendNL( oMenu, "FindItem", mi->itemID );
         if ( HB_ISNIL( -1 ) && !HB_IS_NIL( oPopup ) )
            XA_ObjSendNL( oPopup, "FindItem", mi->itemID );
         }
      else
         if ( !HB_IS_NIL( oPopup ) )
            XA_ObjSendNL( oPopup, "FindItem", mi->itemID );

      if ( !HB_ISNIL( -1 ) )
         {
         hb_itemCopy( oItem, hb_param( -1, HB_IT_OBJECT ) );
         if ( oItem )
            XA_ObjSendNL( oItem, "MeasureItem", (long) mi );
         }

      hb_itemRelease( oItem );
      hb_itemRelease( oPopup );
      hb_itemRelease( oMenu );
      }
   else
      {
      oControl = GetControlFromHandle( GetDlgItem( hWnd, mi->CtlID ) );
      if ( oControl )
         XA_ObjSendNL( oControl, "MeasureItem", hb_parnl( 2 ) );
      }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XFORM_WMCOPYDATA )
{
   PHB_ITEM Self = hb_stackSelfItem();
   LPARAM lParam = (LPARAM) hb_parnl( 2 );
   COPYDATASTRUCT * pcds = (COPYDATASTRUCT *) lParam;
   PHB_DYNS pEvent = hb_dynsymFindName( "ONCOPYDATA" );

   if( pEvent )
   {
      hb_vmPushDynSym( pEvent );
      hb_vmPush( Self );
      hb_vmPushString( (char*) pcds->lpData, pcds->cbData - 1 );
      hb_vmPushLong( pcds->dwData );
      hb_vmSend( 2 );
      if( ! HB_ISNIL( -1 ) )
         hb_retl( -1 );
   }
   else
      hb_retl( FALSE );
}

#pragma ENDDUMP

//--------------------------------------------------------------------------

CLASS TMDIClient FROM TWinControl STATIC

   PROPERTY nAlign   INIT alCLIENT
   PROPERTY lTabStop INIT .T.

PROTECTED:
   DATA cWinClassName      INIT "MDICLIENT"
   PROPERTY lTransparent   INIT .T.

   METHOD CreateMDIClient()

PUBLIC:
   DATA aForms       INIT {}  READONLY AS TForm
   DATA oActiveForm  READONLY AS TForm

   METHOD Create( oParent ) CONSTRUCTOR
   METHOD InsertForm( oForm )
   METHOD RemoveForm( oForm )
   METHOD SetActiveForm( oForm ) INLINE ::oActiveForm := oForm

   METHOD Tile( nFlags )   INLINE ::SendMsg( WM_MDITILE, nFlags )
   METHOD TileHorizontal() INLINE ::SendMsg( WM_MDITILE, 1 )
   METHOD TileVertical()   INLINE ::SendMsg( WM_MDITILE )
   METHOD Cascade()        INLINE ::SendMsg( WM_MDICASCADE )
   METHOD Next()           INLINE ::SendMsg( WM_MDINEXT, 0 )
   METHOD Previous()       INLINE ::SendMsg( WM_MDINEXT, 0, 1 )
   METHOD ArrangeIcons()   INLINE ::SendMsg( WM_MDIICONARRANGE )
   METHOD MaximizeAll()    INLINE AEval( ::aForms, {| oForm | oForm:Maximize() } )
   METHOD MinimizeAll()    INLINE AEval( ::aForms, {| oForm | oForm:Minimize() } )
   METHOD CloseAll()
   METHOD WMSize()         VIRTUAL
   METHOD WMHScroll()      INLINE ::Refresh(), Nil
   METHOD WMVScroll()      INLINE ::Refresh(), Nil
   METHOD WMEraseBkgnd()   INLINE 1
   METHOD WMPaint()        EXTERN XWinControl_WMEraseBkgnd()

ENDCLASS

//------------------------------------------------------------------------------

METHOD Create( oParent ) CLASS TMDIClient

   ::TComponent:Create( oParent )
   ::GetForm()
   ::Register()
   ::hTheme := Nil
   ::nId := ::oForm:GetNewID()
   IF ::CreateMDIClient()
      ::UpdateBounds()
      ::FoParent:InsertControl( Self )
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD InsertForm( oForm ) CLASS TMDIClient

   IF oForm != Nil
      AAdd( ::aForms, oForm )
   ENDIF

RETURN oForm

//--------------------------------------------------------------------------

METHOD RemoveForm( oForm ) CLASS TMDIClient

   LOCAL n

   IF ( n := AScan( ::aForms, {| Obj | oForm == Obj } ) ) > 0
      ADel( ::aForms, n )
      ASize( ::aForms, Len( ::aForms ) - 1 )
      IF Empty( ::aForms )
         ::oActiveForm := Nil
      ENDIF
      ::SendMsg( WM_MDIREFRESHMENU )
      IF Empty( ::aForms )
         ::oParent:SetMdiMenu()
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD CloseAll() CLASS TMDIClient

   WHILE Len( ::aForms ) > 0
      IF !ATail( ::aForms ):Close()
         EXIT
      ENDIF
   ENDDO

RETURN Nil

//--------------------------------------------------------------------------
