Introduction
I will describe here what the article/code snippet does, why it's useful, the problem it solves etc. Splitter is good, but often I need more than just repositioning two panes - implementation of multiple panes, hide/show panes, frozen panes, resize manager, save/load layout. The idea is taken from the new VS.NET C# form editor. You can dock any window at any side or you can set anchor on any side of the window.
Using the code
So we have two kinds of windows - docking and anchored.
The following styles are applicable for docking windows.
SSP_DOCKTOP
- docked at top.
SSP_DOCKBOTTOM
- docked at bottom.
SSP_DOCKLEFT
- docked at left.
SSP_DOCKRIGHT
- docked at right.
SSP_PROPORTIONAL
- pane size (width/height) will be relative to the layout size.
SSP_DOCKFILL
- fill all empty space.
Any docking window can have a splitter - four pixels on opposite side, and splitter can be interactive.
SSP_SPLITTER
- enable splitter (for docking windows only).
SSP_INTERACTIVE
- enable interactive splitter.
And for anchored windows, we have.
SSP_ALIGNLEFT
- left anchor.
SSP_ALIGNRIGHT
- right anchor.
SSP_ALIGNTOP
- top anchor.
AAP_ALIGNBOTTOM
- bottom anchor.
Additionally, one more flag for both types of panes:
SSP_INGNORE
- controls whether layout will be tried to reposition corresponding pane.
For using layout, you need to:
- Derive your own class from
CWindowImpl
/CDialogImpl
and CSharpLayout
.
- Chain message map to
CSharpLayout
.
- Initialize panes.
class CSharpLayoutSampleView : public CDialogImpl<CSharpLayoutSampleView>,
public CSharpLayoutImpl<CSharpLayoutSampleView>
{
public:
enum { IDD = IDD_SHARPLAYOUTSAMPLE_FORM };
BOOL PreTranslateMessage(MSG* pMsg)
{
return CWindow::IsDialogMessage(pMsg);
}
BEGIN_MSG_MAP(CSharpLayoutSampleView)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_1_SHOWTOPDOCKBAR, OnShowTop)
COMMAND_ID_HANDLER(ID_1_SHOWLEFTDOCKBAR, OnShowLeft)
CHAIN_MSG_MAP(CSharpLayoutImpl<CSharpLayoutSampleView>)
END_MSG_MAP()
LRESULT OnShowTop(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
CWindow wnd = GetDlgItem(IDC_EDIT1);
wnd.ShowWindow(wnd.IsWindowVisible() ? SW_HIDE : SW_SHOW);
RecalcLayout();
return 0;
}
LRESULT OnShowLeft(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
CWindow wnd = GetDlgItem(IDC_LIST1);
wnd.ShowWindow(wnd.IsWindowVisible() ? SW_HIDE : SW_SHOW);
RecalcLayout();
return 0;
}
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CMenu menu;
menu.LoadMenu(IDR_CONTEXTMENU);
menu.GetSubMenu(0).TrackPopupMenu(
0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_hWnd);
return 0;
}
LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CMenuHandle menu((HMENU)wParam);
menu.CheckMenuItem(ID_1_SHOWTOPDOCKBAR,
GetDlgItem(IDC_EDIT1).IsWindowVisible() ? MF_CHECKED : MF_UNCHECKED);
menu.CheckMenuItem(ID_1_SHOWLEFTDOCKBAR,
GetDlgItem(IDC_LIST1).IsWindowVisible() ? MF_CHECKED : MF_UNCHECKED);
return 0;
}
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SaveLayout(HKEY_CURRENT_USER, _T("Software\\wtlsplit\\Layout"));
return 0;
}
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SetPaneStyle(GetDlgItem(IDC_EDIT1),
SSP_DOCKTOP|SSP_SPLITTER, false);
SetPaneStyle(GetDlgItem(IDC_LIST1),
SSP_DOCKLEFT|SSP_SPLITTER|SSP_INTERACTIVE|SSP_PROPORTIONAL, false);
SetPaneStyle(GetDlgItem(IDC_BUTTON1),
SSP_ALIGNRIGHT|SSP_ALIGNTOP, false);
SetPaneStyle(GetDlgItem(IDC_BUTTON2),
SSP_ALIGNRIGHT|SSP_ALIGNTOP, false);
SetPaneStyle(GetDlgItem(IDC_BUTTON3),
SSP_ALIGNRIGHT|SSP_ALIGNBOTTOM, false);
SetPaneStyle(GetDlgItem(IDC_EDIT2),
SSP_ALIGNRIGHT|SSP_ALIGNLEFT|SSP_ALIGNBOTTOM|SSP_ALIGNTOP, false);
LoadLayout(HKEY_CURRENT_USER, _T("Software\\wtlsplit\\Layout"), true);
return 0;
}
};
Function reference
There is nothing to comment, all functions are self documented.
bool SetPaneStyle(CWindow wnd, int style, bool update)
bool SetPaneWidth(CWindow wnd, int width, bool update)
bool SetPaneHeight(CWindow wnd, int height, bool update)
bool SetPaneDockSize(CWindow wnd, int size, bool update)
void RecalcLayout()
bool SaveLayout(HKEY hkey, LPCTSTR szkey)
bool LoadLayout(HKEY hkey, LPCTSTR szkey, bool update)
Hope it will be useful!