Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CMagDialog

0.00/5 (No votes)
9 Nov 2005 1  
CMagDialog: a class to enable dialogs to dock side by side.

Screenshot of demo application

Introduction

I started to write this class because I'm often in need to popup additional dialogs around the main one. Often these dialogs can give some trouble to the user; for example, he must move/close them one by one... A solution that could give the application a more solid aspect and that could make the management of the various windows easier could be, to dock all dialogs side by side (like Winamp does, for example).

Background

First of all: when I talk about parent dialog I mean the main dialog and the children are dialogs that can dock to the parent. I know that this isn't exactly the meaning that MS gives to these words but I can't think anything better ;) The class code is really simple. All my work was focused on two points: "the magnetic field" management that enables dialogs to dock, and avoid flickering when windows are forced to dock (i.e. you are inside the field ;)). The first point wasn't a real problem: my solution was to build around the parent dialog four rectangles (one for each side); if the center point of the correspondent child window's edge is inside the rectangle the child is docked.

Here is a snapshot of the code:

//m_pMagParentDlg: pointer to parent window

//pRect: pointer to child window rect

//m_dwMagType: Type of dock (left,right,top,bottom or any side...)


m_pMagParentDlg->GetWindowRect(rectParent);

// Magnetic fields!

rectRight = CRect(rectParent.right-rHight,rectParent.top-rWidth,
     rectParent.right+rHight,rectParent.bottom+rWidth);
//Right magnetic field of parent dialog


curPl = CPoint(pRect->left, 
        pRect->top+(pRect->bottom-pRect->top)/2);
//center point of child's left edge


if ((m_dwMagType == DKDLG_RIGHT || m_dwMagType == DKDLG_ANY) && 

     rectRight.PtInRect(curPl))
{
   m_pMagParentDlg->DockMagneticDialog(this,DKDLG_RIGHT);
   nEdge        = DKDLG_RIGHT;    
   m_bDocked    = TRUE;
}

I spent some time to find a solution to the second problem (avoid flickering). I wanted to reproduce the same effect of Winamp dialogs: childrent that go inside the "magnetic field" of the parent will be pushed to dock. The code behind this effect is simple (a MoveWindow is enough...). The real problem is: where to put the code? Using the ON_WM_MOVING message is bad because this message is cast after the actual window movement so the resulting effect is really ugly (more than a simple flicker!). After some research, I found the right message to catch: ON_WM_WINDOWPOSCHANGING.

The prototype of this function is:

void CMagDialog::OnWindowPosChanging(WINDOWPOS* lpwndpos)

where lpwndpos is a structure that contain the coordinates to which the window will be moved. Filtering these coordinates according to my need is the trick.

void CMagDialog::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
    if ((m_bDocked) &  // This is a fix on movement... 

        (m_pMagParentDlg != NULL) &&
         // I need it only if the windows is docked

         // and I'm trying to move it:

        (m_bDisablePosFix == FALSE))
        // when this window is dragged

        // by parent window I don't need this fix

    {
      CRect tmpRect,rectParent;
      GetWindowRect(tmpRect);
      m_pMagParentDlg->GetWindowRect(rectParent);
      if (nEdge == DKDLG_RIGHT)
      {
        tmpRect.MoveToXY(rectParent.right,lpwndpos->y);
    
      }
    }

    lpwndpos->x  = tmpRect.left;
    lpwndpos->y  = tmpRect.top;
    lpwndpos->cx = tmpRect.Width();
    lpwndpos->cy = tmpRect.Height();

    CDialog::OnWindowPosChanging(lpwndpos);
    //commit changes

}

Using the code

To use magnetic dialogs in your project, simply derive both the parent dialog and the children (see the Background section about the definition of parent and children) from the CMagDialog class. The children must be all modeless dialogs and should be defined inside the parent dialog class (the same thing happens when you are using dockable windows in a DOC/View architecture). Then you must call AddMagneticDialog and EnableMagnetic methods in the parent dialog for each child.

Let's say that m_MyMagDlg is a modeless dialog declared in theparent dialog class. The OnInitDialog will look like:

BOOL CCMagTestDlg::OnInitDialog()
{
   //this child will pop up docked on right side of parent window

   AddMagneticDialog(&m_MyMagDlg,TRUE,DKDLG_RIGHT);
   //and can dock to any side

   m_MyMagDlg.EnableMagnetic(DKDLG_ANY,this);
   m_MyMagDlg.Create(IDD_DIALOG_LIBPREVIEW,this);
   return TRUE;
}

As you can see in the demo, the class also remembers the relative position between the children and the parent so, if you close one child and move around the parent, when you will show the child again, it will placed in the same relative position that it had before.

Overview

These are the definitions of the two public methods of CMagDialog:

void AddMagneticDialog(CMagDialog* pDialog, 
         BOOL bDocked = FALSE,DWORD dwMagWhere =0);
  • PDialog - to child dialog.
  • bDocked - if true, the child window popup is already docked.
  • dwMagWhere - where the dialog docks; can have the following values:
    • DKDLG_ANY
    • DKDLG_LEFT
    • DKDLG_RIGHT
    • DKDLG_TOP
    • DKDLG_BOTTOM
void EnableMagnetic(DWORD dwMagType,CMagDialog* pMagParentDlg);
  • dwMagType - where the dialog can dock; values are the same as dwMagWhere described previously.
  • pMagParentDlg - pointer to the parent dialog window.

Remarks:

dwMagWhere refers to the parent's window side. So DKDLG_LEFT means that children will docked to the left side of the parent window.

History

2005/11/07

  • First public release.

License

This program/code is free and provided "as is" without any expressed or implied warranty. Use at your own risk!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here