1.18.1.4.4 Splitter Dialog

This example shows how to create a splitter dialog, which provides a better display of tree view or grid view.

Ocguide splitter dialog.png

Prepare Dialog Resource

To create this dialog, you first must prepare a dialog resource with a Static control and two Button controls. Here we just use the existing resource IDD_SAMPLE_SPLITTER_DLG in the built-in OriginC\Originlab\ODlg8.dll file to simplify this example.

Prepare Source File

In Code Builder, click New buttonNewfile button.png, type file name, and set Location as the same path of the above dialog resource dll oDlg8.dll - Origin install path OriginC\Originlab subfolder.

Including Header Files

The following header files will be used in the example. Copy the following to the above created source file.

#include <..\Originlab\DialogEx.h>
#include <..\Originlab\SplitterControl.h>
#include <..\Originlab\DynaSplitter.h>

Adding User Defined Splitter Class

We can derive a class from TreeDynaSplitter. Most dialog initialization and other event functions' code are done in a base class and make our splitter class a light class.

class MySplitter : public TreeDynaSplitter
{
public:
	MySplitter(){}
	~MySplitter(){}
	//init the splitter control
	int	Init(int nCtrlID, WndContainer& wndParent, LPCSTR lpcszDlgName = NULL)
	{
		TreeDynaSplitter::Init(nCtrlID, wndParent, 0, lpcszDlgName);
		return 0;
	}
	//output current settings
	void	Output()
	{
		out_tree(m_trSettings);
	}
protected:
	// Declare message map table and message handler
	DECLARE_MESSAGE_MAP
	BOOL	OnInitSplitter();
	BOOL	InitSettings();
	void	OnRowChange(Control ctrl);
	
private:
	BOOL	constructSettings();	
	BOOL	initSystemInfo(TreeNode& trSys);//show system information	
	BOOL	initUserInfo(TreeNode& trUser);//to collect user settings.

private:	
	GridTreeControl	m_List; //grid control on left panel	
	Tree	m_trSettings;//splitter tree on right panel	
	bool	m_bIsInit;//indicate whether it is from init event
	
};

//map the control messages and events.
BEGIN_MESSAGE_MAP_DERIV(MySplitter, TreeDynaSplitter)
	
	ON_INIT(OnInitSplitter) //init splitter settings
	//save splitter size & position when destroy
	//this is done in base class.
	ON_DESTROY(OnDestroy)
	ON_SIZE(OnCtrlResize)
	//when control is ready, need to resize the splitter and its position
	ON_USER_MSG(WM_USER_RESIZE_CONTROLS, OnInitPaneSizs)
	
	//when user select different row on left panel
	ON_GRID_ROW_COL_CHANGE(GetMainPaneID(), OnRowChange)
END_MESSAGE_MAP_DERIV

BOOL	MySplitter::OnInitSplitter()
{
	TreeDynaSplitter::OnInitSplitter(&m_List);
	constructSettings();	//construct tree settings
	InitSettings(); //tree settings to splitter GUI
	SetReady();
	return TRUE;
}

//when user selects a different row, update right panel
void	MySplitter::OnRowChange(Control ctrl)
{
	if ( !m_bReady )
		return;
	//show sub nodes under current branch
	TreeNode trCurrent = ShowListContent(-1, true, m_bIsInit);
	if ( trCurrent )
	{
		//load settings from registry
		string strTag = trCurrent.tagName;
		LoadBranchSetting(GetDlgName(), strTag);
	}
	m_bIsInit = false;
	return;
}

//init splitter settings
BOOL	MySplitter::InitSettings()
{
	m_bIsInit = true;
	///set not ready, avoid flash and painting problem on GUI
	m_bReady = false;
	//set the splitter tree for display
	ShowList(m_trSettings, ATRN_STOP_LEVEL);
	m_bReady = true; //reset ready state.
	SelectRow(0); //select first row.
	return TRUE;
}

BOOL	MySplitter::constructSettings()
{
	TreeNode trSys = m_trSettings.AddNode("System");
	trSys.SetAttribute(STR_LABEL_ATTRIB, "System Information");
	initSystemInfo(trSys);
	
	TreeNode trUser = m_trSettings.AddNode("User");
	trUser.SetAttribute(STR_LABEL_ATTRIB, "User Settings");
	initUserInfo(trUser);
	return TRUE;
}

//display your Origin's basic information.
//you can also display OS related information here.
BOOL	MySplitter::initSystemInfo(TreeNode& trSys)
{
	if ( !trSys )
		return FALSE;
	
	char szUser[LIC_USERINFO_NAME_COMPANY_MAXLEN];
	char szCompany[LIC_USERINFO_NAME_COMPANY_MAXLEN];
	char szSerial[LIC_OTHER_INFO_MAXLEN];
	char szRegCode[LIC_OTHER_INFO_MAXLEN];
	DWORD dwProd = GetLicenseInfo(szUser, szCompany, szSerial, szRegCode);
	string strProduct;
	switch( dwProd & 0x000000FF )
	{
	case ORGPRODUCTTYPE_EVALUATION:
		strProduct = "Evaluation";
		break;
	case ORGPRODUCTTYPE_STUDENT:
		strProduct = "Student";
		break;
	case ORGPRODUCTTYPE_REGULAR:
		strProduct = "Regular";
		break;
	case ORGPRODUCTTYPE_PRO:
		strProduct = "Professional";
		break;
	default:
		strProduct = "Unknown";
		break;
	}

	GETN_USE(trSys)
	GETN_STR(UserName, "User Name", szUser)
	GETN_READ_ONLY_EX(2)
	GETN_STR(Company, "Company Name", szCompany)
	GETN_READ_ONLY_EX(2)
	GETN_STR(SeriNum, "Serial Number", szSerial)
	GETN_READ_ONLY_EX(2)
	GETN_STR(RegCode, "Register Code", szRegCode)
	GETN_READ_ONLY_EX(2)
	GETN_STR(Product, "Product Version", strProduct)
	GETN_READ_ONLY_EX(2)
	return TRUE;
}

//controls to collect user information and settings.
BOOL	MySplitter::initUserInfo(TreeNode& trUser)
{
	if ( !trUser )
		return FALSE;

	GETN_USE(trUser)
	GETN_STRLIST(Language, "Language", "English", "|English|German")
	GETN_STR(UserID, "User ID", "")
	GETN_PASSWORD(Password, "Password", "")
	GETN_STR(Email, "Email", "user@originlab.com")
	
	return TRUE;
}

Adding User Defined Splitter Dialog Class

The splitter dialog contains a splitter control object, so the dialog can initialize the splitter control and post messages to it on the proper events.

//dialog name, which will also be used to save settings in registry
#define	STR_DLG_NAME	"My Splitter Dialog"
class MySplitterDlg : public MultiPaneDlg
{
public:
	//resource ID and which DLL contains this dialog resource
	MySplitterDlg() : MultiPaneDlg(IDD_SAMPLE_SPLITTER_DLG, "ODlg8")
	{
	}
	~MySplitterDlg()
	{
	}
	//open dialog until user close it.
	int	DoModalEx(HWND hParent = NULL)
	{
		//set up message map
		InitMsgMap();
		return DoModal(hParent, DLG_NO_DEFAULT_REPOSITION);
	}
	//init controls and other settings before dialog open
	BOOL	OnInitDialog();
	//when dialog initialization finish
	BOOL	OnReady();
	//when user click 'Output' button
	BOOL	OnOutput(Control ctrl);
protected:
	DECLARE_MESSAGE_MAP
private:
	MySplitter	m_Splitter;
	
};

//map dialog message
BEGIN_MESSAGE_MAP(MySplitterDlg)
	ON_INIT(OnInitDialog)
	ON_READY(OnReady)
	ON_BN_CLICKED(IDC_LOAD, OnOutput)
END_MESSAGE_MAP

BOOL	MySplitterDlg::OnInitDialog()
{
	//rename buttons title to meaningful text
	GetDlgItem(IDC_LOAD).Text = "Output";
	GetDlgItem(IDCANCEL).Text = "Close";
	m_Splitter.Init(IDC_FB_BOX, *this, STR_DLG_NAME);
	return TRUE;
}

BOOL	MySplitterDlg::OnReady()
{
	//update dialog
	UpdateDlgShow();
	SetInitReady();
	//set splittercontrol ready as to init the position and size
	m_Splitter.OnReady();
	return TRUE;
}

BOOL	MySplitterDlg::OnOutput(Control ctrl)
{
	//dump current user settings.
	m_Splitter.Output();
	return TRUE;
}

Open Dialog

After the steps above, save all the code and build it, then execute the following function to open the splitter dialog.

void	test_MySplitterDlg()
{
	MySplitterDlg dlg;
	dlg.DoModalEx(GetWindow());
}