Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Request to add "pre-create" message for CExtDynControlBars Collapse All
Subject Author Date
Dmitriy Dashevskiy Oct 22, 2005 - 9:05 AM

I would like to save state of control bars in CChildFrame when it changes, so that when new child is created it will have same layout.

To do it I have to overwrite some functions.

in class derived from CExtControlBar

   /*virtual*/ void _DraggingStop( bool bCancel );     //to catch changes in docking layout
   /*virtual*/ void _RowResizingStop( bool bCancel );  //to catch resizing when docked by itself
   /*virtual*/ void _RowRecalcingStop( bool bCancel ); //to catch resizing within CExtDynControlBars


in class derived from CExtBarNcAreaButtonAutoHide and used in OnNcAreaButtonsReinitialize when creating autohidden buttons for my controlbar and tabbedbar
   /*virtual*/ bool OnNcAreaClicked( CPoint point );      //to catch when  bars are autohidden/restored by user


As I can see from the code Prof-UIS creates two "internal containers" when docking control bars: CExtDynTabControlBar and CExtDynControlBars

With CExtDynTabControlBar it is easy:
class derived from CExtDynTabControlBar and created on CExtControlBar::g_nMsgCreateTabbedBar message
   /*virtual*/ void _DraggingStop( bool bCancel );    //to catch changes in docking layout when controlBars are in tab bar
   /*virtual*/ void _RowResizingStop( bool bCancel ); //to catch resizing when controlBars are in tab bar


But there is no message when CExtDynControlBars are created dynamicaly. With such message it will be possible to overwrite needed functions
in class derived from CExtDynControlBars and created on CExtControlBar::g_nMsgCreateDynBar message
   /*virtual*/ void _RowResizingStop( bool bCancel ); //to catch resizing of dynamic bar


I’ve done some modifications in current version of the library and everything seems to work fine. If you think it is appropriate, could you please add folowing modifications to the library? Thank you in advance.

1. add variable to CExtControlBar
	static const UINT g_nMsgCreateDynBar;

const UINT CExtControlBar::g_nMsgCreateDynBar =
	::RegisterWindowMessage(
		_T("CExtControlBar::g_nMsgCreateDynBar")
		);


2. replace in CExtControlBar::_DraggingDoDeepHalfSplit
CExtDynControlBar* pDynBar = new CExtDynControlBar;

with
CExtDynControlBar* pDynBar = NULL;
   m_pDockSite->SendMessage(
		g_nMsgCreateDynBar,
		WPARAM( &pDynBar )
		);
#ifdef _DEBUG
	if( pDynBar != NULL )
	{
		ASSERT_VALID( pDynBar );
		ASSERT_KINDOF( CExtDynControlBar, pDynBar );
	} // if( pDynBar != NULL )
#endif // _DEBUG
	if( pDynBar == NULL )
		pDynBar = new CExtDynControlBar;


3. replace in CExtDynamicBarHookSink::OnHookWndMsg
#if (!defined __EXT_MFC_NO_TAB_CONTROLBARS)
			if( nMessage == CExtControlBar::g_nMsgCreateTabbedBar )
			{
				lResult = 0L;
				CExtDynTabControlBar ** ppTabbedBar =
					(CExtDynTabControlBar **)wParam;
				ASSERT( ppTabbedBar != NULL );
				(*ppTabbedBar) = pDBS->OnDbsCreateTabbedBarInstance();
				ASSERT( (*ppTabbedBar) != NULL );
				return true;
			} // if( nMessage == CExtControlBar::g_nMsgCreateTabbedBar )
#endif // (!defined __EXT_MFC_NO_TAB_CONTROLBARS)

with
#if (!defined __EXT_MFC_NO_TAB_CONTROLBARS)
			if( nMessage == CExtControlBar::g_nMsgCreateTabbedBar )
			{
				lResult = 0L;
				CExtDynTabControlBar ** ppTabbedBar =
					(CExtDynTabControlBar **)wParam;
				ASSERT( ppTabbedBar != NULL );
				(*ppTabbedBar) = pDBS->OnDbsCreateTabbedBarInstance();
				ASSERT( (*ppTabbedBar) != NULL );
				return true;
			} // if( nMessage == CExtControlBar::g_nMsgCreateTabbedBar )
#endif // (!defined __EXT_MFC_NO_TAB_CONTROLBARS)

			if( nMessage == CExtControlBar::g_nMsgCreateDynBar )
			{
				lResult = 0L;
				CExtDynControlBar ** ppDynBar =
					(CExtDynControlBar **)wParam;
				ASSERT( ppDynBar != NULL );
				(*ppDynBar) = pDBS->OnDbsCreateDynBarInstance();
				ASSERT( (*ppDynBar) != NULL );
				return true;
			} // if( nMessage == CExtControlBar::g_nMsgCreateDynamicBar )


4. replace in CExtControlBar::InternalDockStateBar::StateSet
		m_pHelperBar = new CExtDynControlBar;

with
		m_pHelperBar = NULL;
      pDockSite->SendMessage(
		   g_nMsgCreateDynBar,
		   WPARAM( &m_pHelperBar )
		   );
      #ifdef _DEBUG
	      if( m_pHelperBar != NULL )
	      {
		      ASSERT_VALID( m_pHelperBar );
		      ASSERT_KINDOF( CExtDynControlBar, m_pHelperBar );
	      } // if( m_pHelperBar != NULL )
      #endif // _DEBUG
	   if( m_pHelperBar == NULL )
		   m_pHelperBar = new CExtDynControlBar;



5. add to CExtDynamicBarSite class
	virtual CExtDynControlBar * OnDbsCreateNewDynBarInstance() const;


CExtDynControlBar * CExtDynamicBarSite::OnDbsCreateNewDynBarInstance() const
{
	ASSERT( this != NULL );
	return new CExtDynControlBar;
}

Technical Support Oct 25, 2005 - 6:24 AM

It’s not a good idea to save the control bars’ state when the position of some control bar changes. For example, the floating control bar is changing its position during drag-and-drop when the Visual Studio 2005 docking algorithm is used. The state of control bars is defined by a complex, tree-like data structure serialized into the archive. So, we do not recommend you save it each time when the user drag-and-drops some control bar.

What you want to implement can be done in a much easier and elegant way: Handle the WM_CREATE message in a CMDIChildWnd-derived class, find any previously created MDI child frame instance of the same type, ask it to save the bar state and continue loading the bar state in the MDI child frame window being created. Your code may look like:

int CYourChildFrame::OnCreate(
    LPCREATESTRUCT lpCreateStruct
    )
{
    . . .
 
    // configure everything needed and create all the bars
    . . .
 
    // find any other child frame of the same type
HWND hWndMdiClient = ::GetParent( m_hWnd );
HWND hWndMdiChildFrame = ::GetWindow( hWndMdiClient, GW_CHILD );
    for( ; hWndMdiChildFrame != NULL;
         hWndMdiChildFrame = ::GetWindow( hWndMdiChildFrame, GW_HWNDNEXT ) )
    {
        if( hWndMdiChildFrame == m_hWnd )
            continue;
        CWnd * pWnd = CWnd::FromHandlePermanent( hWndMdiChildFrame );
        if(  pWnd == NULL )
            continue;
        CYourChildFrame * pOtherFrame =
            DYNAMIC_DOWNCAST( CYourChildFrame, CYourChildFrame );
        if( pOtherFrame == NULL )
            continue;
        // ask other frame to save its bar state
        pOtherFrame->DoSaveBarState();
        break;
    }
 
    // continue loading bar state here
    . . .
}


Dmitriy Dashevskiy Oct 25, 2005 - 12:03 PM

Yes, saving state only when new window is created (old closed) is faster. But still it is necessary to know what window holds -modified- layout. Say, there are two child windows already created, then one is modified and third one is created. It is possible to get second (nonmodified) one when looking for similar window and save its state. Some flag to know that state has been modified is needed anyway. To get it right it is necessary to handle all possible modification events (resizing and redocking). As was said above it can’t be done externaly without supplying user defined CExtDynControlBar-based class.

Technical Support Oct 26, 2005 - 7:49 AM

A change in the size or position of a resizable control bar window typically affects other control bars and may also affect toolbars. A change in the toolbar position may affect the size of one or more control bars when, for example, a single toolbar docked at the top becomes floating. The notification of a change in a bar of any kind leads to the same notifications to be fired for many other bars. So, we need to additionally think about how to make these notifications convenient and helpful.