home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / powergui / advframe / mdi / mdiwin.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-29  |  14.4 KB  |  443 lines

  1. //************************************************************
  2. // Advanced Frame - MDI Frame Example
  3. //
  4. // Copyright (C) 1994, Law, Leong, Love, Olson, Tsuji.
  5. // Copyright (c) 1997 John Wiley & Sons, Inc. 
  6. // All Rights Reserved.
  7. //************************************************************
  8. #include <windows.h>
  9. #include <icmdhdr.hpp>
  10. #include <icoordsy.hpp>
  11. #include <iexcept.hpp>
  12. #include <imenubar.hpp>
  13. #include <isysmenu.hpp>
  14. #include <ithread.hpp>
  15. #include "mdiwin.hpp"
  16.  
  17. class CmdHandler : public ICommandHandler {
  18. public:
  19.   CmdHandler();
  20. virtual Boolean
  21.   systemCommand ( ICommandEvent& event );
  22. static CmdHandler
  23.   *defaultHandler();
  24. private:
  25.  static CmdHandler
  26.    *defaultHdr;
  27. };
  28.  
  29. CmdHandler* CmdHandler::defaultHdr = 0;
  30.  
  31. CmdHandler::CmdHandler()
  32.   : ICommandHandler()
  33. { }
  34.  
  35. IBase::Boolean CmdHandler::systemCommand( ICommandEvent& event )
  36. {
  37.   Boolean handled = false;
  38.   if ((event.commandId() & 0xFFF0 ) == SC_CLOSE )
  39.     {
  40.     MDIWindow* mdichild = (MDIWindow*)event.window();
  41.     if (mdichild)
  42.       {
  43.       mdichild->close();
  44.       handled = true;
  45.       }
  46.     }
  47.   return handled;
  48. }
  49.  
  50. CmdHandler* CmdHandler::defaultHandler( )
  51. {
  52.   if (!CmdHandler::defaultHdr)
  53.     CmdHandler::defaultHdr = new CmdHandler;
  54.   return CmdHandler::defaultHdr;
  55. }
  56.  
  57. MDIWindow::MDIWindow( const IResourceId&         resId,
  58.                       IWindow*                   parent ,
  59.                       IWindow*                   owner ,
  60.                       unsigned long              windowMenuId,
  61.                       unsigned long              childMenuId,
  62.                       const IRectangle&          initRect,
  63.                       const IFrameWindow::Style& style,
  64.                       const char*                title  ) :
  65.   IFrameWindow ( IFrameWindow::deferCreation ),
  66.   fclient      ( 0 ),
  67.   fchildId     ( childMenuId )
  68. {
  69.    // Use MDIWindow::initialize instead of the one in IFrameWindow.
  70.    this->initialize( resId, style, parent,
  71.                      owner, initRect, title );
  72.  
  73.    // Create the MDI client window.
  74.    IMenuBar menu( this, IMenuBar::wrapper );
  75.    CLIENTCREATESTRUCT ccs;
  76.    ccs.hWindowMenu = menu.menuItem( windowMenuId ).submenuHandle();
  77.    ccs.idFirstChild = (unsigned int)fchildId;
  78.    IWindowHandle hwnd =
  79.      IWindow::create( IC_FRAME_CLIENT_ID,
  80.                       0,
  81.                       WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL |
  82.                       WS_HSCROLL | WS_VISIBLE ,
  83.                       "MDICLIENT",
  84.                       this->handle(),
  85.                       this->handle(),
  86.                       IRectangle(0,0,0,0),
  87.                       &ccs,
  88.                       0,
  89.                       defaultOrdering(),
  90.                       0 );
  91.    fclient = new IWindow( hwnd );
  92.    fclient->setAutoDeleteObject( true );
  93. }
  94.  
  95. MDIWindow::MDIWindow( const IResourceId&         resId,
  96.                       MDIWindow*                 parent,
  97.                       const IRectangle&          initRect,
  98.                       const IFrameWindow::Style& style,
  99.                       const char*                title) :
  100.   IFrameWindow ( IFrameWindow::deferCreation ),
  101.   fclient  ( 0 ),
  102.   fchildId ( 0 )
  103. {
  104.    IASSERTPARM( (parent != 0) && (parent->client() != 0) );
  105.    // Use MDIWindow::initialize instead of the one in IFrameWindow.
  106.    this->initialize( resId, style, parent->client(),
  107.                      parent->client(), initRect, title );
  108.    CmdHandler::defaultHandler()->handleEventsFor( this );
  109. }
  110.  
  111. MDIWindow& MDIWindow::setClient    ( IWindow* newClient )
  112. {
  113.   if (fclient == 0)
  114.      IFrameWindow::setClient( newClient );
  115.   return *this;
  116. }
  117.  
  118. MDIWindow &MDIWindow::close ( )
  119.   {
  120.   IWindow* mdiClient = fclient ? 0 : this->parent();
  121.   if (mdiClient)
  122.      mdiClient->sendEvent( WM_MDIDESTROY,
  123.                            IEventParameter1(this->handle()) );
  124.   else
  125.      IFrameWindow::close();
  126.   return *this;
  127.   }
  128.  
  129. MDIWindow &MDIWindow::maximize ( )
  130. {
  131.   IWindow* mdiClient = fclient ? 0 : this->parent();
  132.   // Ignore the request if there is no maximize button.
  133.   if ((this->style() & WS_MAXIMIZEBOX ) && (mdiClient) )
  134.      mdiClient->sendEvent( WM_MDIMAXIMIZE,
  135.                            IEventParameter1(this->handle()) );
  136.   else
  137.      IFrameWindow::maximize();
  138.   return *this;
  139. }
  140.  
  141. MDIWindow &MDIWindow::restore ( )
  142. {
  143.   IWindow* mdiClient = fclient ? 0 : this->parent();
  144.   if (mdiClient)
  145.      mdiClient->sendEvent( WM_MDIRESTORE,
  146.                            IEventParameter1(this->handle()) );
  147.   else
  148.      IFrameWindow::restore();
  149.   return *this;
  150. }
  151.  
  152. // This function returns the active MDI child or 0 if there
  153. // is none.
  154. MDIWindow*  MDIWindow::activeChild( ) const
  155. {
  156.   MDIWindow* child = 0;
  157.   if (fclient)
  158.     child = (MDIWindow*) IWindow::windowWithHandle(
  159.                 (HANDLE)fclient->sendEvent( WM_MDIGETACTIVE ));
  160.   return child;
  161. }
  162.  
  163. MDIWindow&  MDIWindow::activateChild( unsigned long childId )
  164. {
  165.   if ((childId >= fchildId) && (fclient))
  166.      {
  167.      IWindow* child =
  168.         IWindow::windowWithParent( childId, fclient );
  169.      if (child)
  170.         fclient->sendEvent( WM_MDIACTIVATE,
  171.                             IEventParameter1(child->handle()) );
  172.      }
  173.   return *this;
  174. }
  175.  
  176. MDIWindow&  MDIWindow::arrange        ( )
  177. {
  178.   IWindow* mdiClient = fclient ? fclient : this->parent();
  179.   if (mdiClient)
  180.      mdiClient->sendEvent( WM_MDIICONARRANGE );
  181.   return *this;
  182. }
  183.  
  184. MDIWindow&  MDIWindow::cascade        ( )
  185. {
  186.   IWindow* mdiClient = fclient ? fclient : this->parent();
  187.   if (mdiClient)
  188.      mdiClient->sendEvent( WM_MDICASCADE );
  189.   return *this;
  190. }
  191.  
  192. MDIWindow&  MDIWindow::tile           ( Boolean horizontal )
  193. {
  194.   IWindow* mdiClient = fclient ? fclient : this->parent();
  195.   if (mdiClient)
  196.      mdiClient->sendEvent( WM_MDITILE,
  197.                            horizontal ? MDITILE_HORIZONTAL :
  198.                                         MDITILE_VERTICAL);
  199.   return *this;
  200. }
  201.  
  202. MDIWindow& MDIWindow::initialize ( const IResourceId &resId,
  203.                                  const Style       &style,
  204.                                  IWindow           *parent,
  205.                                  IWindow           *owner,
  206.                                  const IRectangle  &initRect,
  207.                                  const char        *title )
  208. {
  209.   // Save the extended style.
  210.   setExtendedStyle(
  211.      extendedStyle() | style.asExtendedUnsignedLong() );
  212.  
  213.   // Get styles and set up values for parent and owner windows.
  214.   unsigned long
  215.     frameStyle   = convertToGUIStyle( style ),
  216.     exFrameStyle = convertToGUIStyle( style, true );
  217.   IWindowHandle
  218.     hParent = ( parent ) ? parent->handle() :
  219.                            IWindow::desktopWindow()->handle(),
  220.     hOwner  = ( owner )  ? owner->handle()  : IWindowHandle( 0 );
  221.   Boolean
  222.     isChild = ( hParent != IWindow::desktopWindow()->handle() );
  223.  
  224.   if ( isChild )
  225.      frameStyle |= WS_CHILD;
  226.   else
  227.      frameStyle &= ~(unsigned long)WS_CHILD;
  228.  
  229.   // Try to get the title from the resource library.  If it
  230.   // is not available, use whatever was provided.
  231.   HANDLE   fcdata = resId.resourceLibrary().handle();
  232.   if ( style & IFrameWindow::titleBar && !title )
  233.      {
  234.      IString titleString =
  235.         resId.resourceLibrary().tryToLoadString( resId.id() );
  236.      if ( titleString.length() )
  237.         title = titleString;
  238.      }
  239.   else if ( !(style & IFrameWindow::titleBar) )
  240.      {
  241.      // The WS_OVERLAPPED style implies title bar.  Make it a
  242.      // pop-up window if the title bar area is not needed for
  243.      // buttons or the system menu.
  244.      if (!(frameStyle &
  245.            (WS_CHILD|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_SYSMENU)))
  246.         frameStyle |= WS_POPUP;
  247.      }
  248.  
  249.   IRectangle rect = ( style & IFrameWindow::shellPosition ) ?
  250.                     IFrameWindow::nextShellRect() : initRect;
  251.  
  252.   // Create our window class for the frame if necessary.
  253.   char* frameClass = (char*)
  254.     registerFrameClass( style, resId, isChild );
  255.  
  256.   // Create the window.  For Windows 95 and Windows NT 4.0,
  257.   // the WS_EX_MDICHILD extended style can be used with
  258.   // IFrameWindow::create to create an MDI child window.
  259.   // This style is not supported in Windows NT 3.51, so
  260.   // we have to use a more complex approach to support
  261.   // all operating systems.
  262.   if (isChild)
  263.      {
  264.      // Use CreateMDIWindow to create the MDI child.
  265.      RECT parentRect;
  266.      GetClientRect(hParent, &parentRect);
  267.      ISize parentSize = ISize(parentRect.right - parentRect.left,
  268.                               parentRect.bottom - parentRect.top);
  269.      rect = ICoordinateSystem::convertToNative( rect, parentSize);
  270.      IWindowHandle hwnd = CreateMDIWindow(
  271.                              frameClass,
  272.                              (LPSTR)title,
  273.                              frameStyle,
  274.                              (int)rect.minX(),
  275.                              (int)rect.minY(),
  276.                              (int)rect.width(),
  277.                              (int)rect.height(),
  278.                              hParent,
  279.                              GetModuleHandle(0),
  280.                              0);
  281.      // Complete the functions IFrameWindow::create
  282.      // would have completed.
  283.      this->start( hwnd );
  284.      this->setOwner( owner );
  285.      // CreateMDIWindow forces WS_VISIBLE to on. Undo this for now.
  286.      this->hide();
  287.      }
  288.   else
  289.      {
  290.      // Use IFrameWindow::create so we get the resource and
  291.      // menu handling functions it provides.
  292.      this -> create( resId.id(),
  293.                      title,
  294.                      frameStyle & (unsigned long)~WS_VISIBLE,
  295.                      frameClass,
  296.                      hParent,
  297.                      hOwner,
  298.                      rect,
  299.                      fcdata,
  300.                      0,
  301.                      defaultOrdering(),
  302.                      exFrameStyle );
  303.      }
  304.  
  305.  
  306.   // If one or both of the minimize/maximize buttons is missing
  307.   // and there is still a system menu, disable the corresponding
  308.   // item in the system menu.  Disabling rather than removing is
  309.   // the action recommended in the SDK.
  310.   if (frameStyle & WS_SYSMENU)
  311.      {
  312.      if ( (frameStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) !=
  313.           (WS_MINIMIZEBOX | WS_MAXIMIZEBOX) )
  314.         {
  315.         ISystemMenu sysMenu( this );
  316.         if ( !(frameStyle & WS_MINIMIZEBOX) )
  317.            sysMenu.disableItem( ISystemMenu::idMinimize );
  318.         if ( !(frameStyle & WS_MAXIMIZEBOX) )
  319.            sysMenu.disableItem( ISystemMenu::idMaximize );
  320.         // Restore is left enabled when the
  321.         // WS_EX_DLGMODALFRAME style is used
  322.         if ((exFrameStyle & WS_EX_DLGMODALFRAME) &&
  323.             ((frameStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX))==0))
  324.            sysMenu.disableItem( ISystemMenu::idRestore );
  325.         }
  326.      }
  327.  
  328.   // Handle requests to minimize or maximize the window.
  329.   if ( style & IFrameWindow::minimized )
  330.      this -> minimize();
  331.   else if ( style & IFrameWindow::maximized )
  332.      this -> maximize();
  333.  
  334.   // Handle request to show the window.
  335.   if ( style & IWindow::visible )
  336.      this -> show();
  337.  
  338.   return *this;
  339.   }
  340.  
  341.  
  342. static LRESULT CALLBACK MDIWindowProc( void*        hwnd,
  343.                                       unsigned int eventId,
  344.                                       WPARAM       parm1,
  345.                                       LPARAM       parm2 )
  346. {
  347.   MDIWindow* frame = (MDIWindow*)IWindow::windowWithHandle( hwnd );
  348.   if (frame)
  349.      {
  350.      return DefFrameProc( hwnd,
  351.                           frame->clientHandle(),
  352.                           eventId,
  353.                           parm1,
  354.                           parm2);
  355.      }
  356.   else
  357.      {
  358.      return CallWindowProc( (FARPROC)DefWindowProc,
  359.                             hwnd,
  360.                             eventId,
  361.                             parm1,
  362.                             parm2);
  363.      }
  364. }
  365.  
  366. unsigned long MDIWindow::registerFrameClass(
  367.                             const Style& style,
  368.                             const IResourceId& resId,
  369.                             Boolean isChild )
  370. {
  371.   // Create a WNDCLASS structure for registering the new class.
  372.   // We base this class on the WC_DIALOG class, but set up the
  373.   // background brush, class style, and icon to match those
  374.   // specified for the MDIWindow.  IFrameWindow uses the extra
  375.   // window word.
  376.   WNDCLASS
  377.     wndclass;
  378.   if (!GetClassInfo( 0, WC_DIALOG, &wndclass))
  379.      ITHROWGUIERROR( "GetClassInfo" );
  380.   if (style & IFrameWindow::dialogBackground )
  381.     wndclass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
  382.   else
  383.     wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  384.   wndclass.cbWndExtra = DLGWINDOWEXTRA + 4;
  385.   wndclass.style =
  386.      CS_DBLCLKS | CS_OWNDC | CS_VREDRAW | CS_HREDRAW ;
  387.   if ( !( style & IFrameWindow::alignNoAdjust ) )
  388.      wndclass.style |= CS_BYTEALIGNWINDOW;
  389.  
  390.   // If the minimizedIcon style is set, load the icon resource
  391.   // and place it into the class structure. Otherwise, use the
  392.   // default icon for dialogs.
  393.   if ( style & IFrameWindow::minimizedIcon )
  394.      {
  395.      HINSTANCE
  396.         hInstance = resId.resourceLibrary().handle();
  397.      HICON
  398.        hIcon;
  399.      if ( !(hIcon = LoadIcon(
  400.                       hInstance, MAKEINTRESOURCE( resId.id() ))))
  401.         ITHROWGUIERROR( "LoadIcon" );
  402.      else
  403.         wndclass.hIcon = hIcon;
  404.      }
  405.   wndclass.lpszMenuName = 0;
  406.   wndclass.hInstance = GetModuleHandle(0);
  407.  
  408.   // Here is the key difference between the MDIWindow window class
  409.   // and the ones created by IFrameWindow.  We arrange for the
  410.   // special MDI window procedures to be called.
  411.   if (isChild)
  412.     wndclass.lpfnWndProc = DefMDIChildProc;
  413.   else
  414.     wndclass.lpfnWndProc = (WNDPROC)MDIWindowProc;
  415.  
  416.   // Register a class whose name is ICL Frame_MDI + nnnn,
  417.   // where nnnn is the ASCII string for the value of classID.
  418.   // This results in each frame window having a unique class name
  419.   // similar to ICL Frame_MDI1.
  420.   ATOM
  421.      frameClass = 0;
  422.   static unsigned long
  423.      classID = 0;
  424.   do
  425.      {
  426.      IString newFrameClass =  IString("ICL Frame_MDI") +
  427.                               IString(classID);
  428.      classID++;
  429.      wndclass.lpszClassName = newFrameClass;
  430.      frameClass = RegisterClass( &wndclass );
  431.      if (!frameClass)
  432.         {
  433.         // If the class exists, try again with the next ID value.
  434.         // Otherwise, throw an exception.
  435.         if (GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
  436.            ITHROWGUIERROR( "RegisterClass" );
  437.         }   // if not registered
  438.      }
  439.   while (!frameClass);
  440.  
  441.   return MAKELONG( frameClass, 0 );
  442. }
  443.