Monthly Archives: December 2013

Upgrading my MFC project and Boost to Visual C++ 2013

First of all, my modeler project hosted at codeplex is compiled with Visual C++ 2012 and vc10 compiler toolset. Why the vc10 compiler ? I use Boost serialization library and sourceforge gives me a static lib called libboost_serialization-vc100-mt-gd-1_51.lib built using vc10. Switching to Visual Studio 2013, I decided to build every thing with Visual C++ 2013, even boost.

First step : building Boost

My project use Boost 1.51 and there are some issue with Boost latest version 1.55 with the serialization library and vc12 (Visual C++ 2013) so I stay with Boost 1.51. There are two commands to launch. The first is bootstrap.bat and the second one is:

> bjam toolset=msvc-12.0 variant=debug,release threading=multi link=shared

The result is in the boost \ stage \ lib folder.

Second step: updating MFC setup

Download the MFC120.dll regular dll from http://www.microsoft.com/en-us/download/details.aspx?id=40770. If your project is built with Unicode character set, it will go OK but if you use not set or multibyte, you can’t compile…

Third step: modify Boost includes to handle a proper link to vc12

Modify the boost_1_51_0\boost\config\auto_link.hpp to handle vc12 (Visual C++ 2013). Add this line 158.

#elif defined(BOOST_MSVC) && (BOOST_MSVC == 1800)
// vc12:
#  define BOOST_LIB_TOOLSET “vc120”

Fourth step: modify my project to use Boost as Dynamic Library for Serialization library

In the stdafx.h, I just add the following defines before including Boost headers:

#define BOOST_SERIALIZATION_DYN_LINK TRUE
#define BOOST_ALL_DYN_LINK TRUE

Implementing a full Ribbon in a native application (more)

Here is my ribbon in my application:

modeler1_ribbon

The first item to create is the circle button that acts as the file menu. It is done using CMFCRibbonMainPanel class.

Then you create a category called Home using CMFCRibbonCategory class.

After this step, you have to create panels using CMFCRibbonPanel class.

Inside your panel, you can create button, combo box and galley using CMFCRibbonButton class, CMFCRibbonComboBox class, CMFCRibbonGallery  class.

Here is the whole source code:


void CMainFrame::InitMainButton()
{
m_MainButton.SetImage(IDB_RIBBON_MAIN);
m_MainButton.SetToolTipText(_T("File"));
m_MainButton.SetText(_T("\nf"));

CreateDocumentColors();

m_wndRibbonBar.SetApplicationButton(&m_MainButton, CSize(45, 45));

CMFCRibbonMainPanel* pMainPanel = m_wndRibbonBar.AddMainCategory(_T("File"), IDB_RIBBON_FILESMALL, IDB_RIBBON_FILELARGE);
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_NEW, _T("&New"), 0, 0));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN, _T("&Open..."), 1, 1));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_OPEN_AS_XML, _T("Open As XML..."), 1, 1));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE, _T("&Save"), 2, 2));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS, _T("Save &As..."), 3, 3));
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_SAVE_AS_XML, _T("Save As &XML..."), 3, 3));
pMainPanel->AddSeparator();
pMainPanel->Add(new CMFCRibbonButton(ID_FILE_CLOSE, _T("&Close"), 8, 8));
pMainPanel->AddRecentFilesList(_T("Recent Documents"));
pMainPanel->AddToBottom(new CMFCRibbonMainPanelButton(ID_APP_EXIT, _T("E&xit"), 27));

CMFCRibbonCategory* pCategory = m_wndRibbonBar.AddCategory(_T("&Home"), IDB_RIBBON_WRITESMALL, IDB_RIBBON_WRITELARGE);
// Create "Design" panel
CMFCRibbonPanel* pPanelDesign = pCategory->AddPanel(_T("Design\nzd"), m_PanelImages.ExtractIcon(2));
pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_SELECT, _T("Select\nc"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_RECTANGLE, _T("Rectangle\ng"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_LINE, _T("Line\ng"), 2));
//pPanelDesign->Add(new CMFCRibbonButton(ID_DESIGN_ELLIPSE, _T("Ellipse\ng"), 2));

CMFCRibbonButton* pInsertPictureBtn = new CMFCRibbonButton(ID_DESIGN_IMAGE, _T("Picture"), 4, 4);
pPanelDesign->Add(pInsertPictureBtn);

CMFCRibbonGallery *pInsertShapesBtn = new CMFCRibbonGallery(ID_DESIGN_SHAPES, _T("Shapes"), 6, 6);
pInsertShapesBtn->SetButtonMode();
pInsertShapesBtn->SetIconsInRow(12);
pInsertShapesBtn->AddGroup(_T("Recently Used Shapes"), IDB_SHAPE1, 20);
pInsertShapesBtn->AddGroup(_T("Lines"), IDB_SHAPE2, 20);
pInsertShapesBtn->AddGroup(_T("Basic Shapes"), IDB_SHAPE3, 20);
pInsertShapesBtn->AddGroup(_T("Block Arrows"), IDB_SHAPE4, 20);
pInsertShapesBtn->AddGroup(_T("Flowchart"), IDB_SHAPE5, 20);
pInsertShapesBtn->AddGroup(_T("Callouts"), IDB_SHAPE6, 20);
pInsertShapesBtn->AddGroup(_T("Stars and Banners"), IDB_SHAPE7, 20);
pInsertShapesBtn->AddSubItem(new CMFCRibbonButton(ID_DESIGN_SHAPES_NEW, _T("&New Drawing Canvas"), 29, -1));
pPanelDesign->Add(pInsertShapesBtn);

CMFCRibbonButton* pBtnDrawText = new CMFCRibbonButton(ID_DESIGN_TEXTBOX, _T("Draw Text Box\nx"), 15, 15);
pBtnDrawText->SetMenu(IDR_DRAW_TEXT_MENU);
pPanelDesign->Add(pBtnDrawText);
// Add hidden button
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_LEFT, _T("&Bottom Border"), 28));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_CENTER, _T("Paste Special"), 29));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_RIGHT, _T("Paste Special"), 30));
pCategory->AddHidden(new CMFCRibbonButton(ID_TEXT_JUSTIFY, _T("Paste Special"), 31));

CRibbonListButton *pListBtnInfra = new CRibbonListButton(ID_DESIGN_SHAPESINFRA, _T("Infrastructure\nti"), 20, -1, FALSE);
pListBtnInfra->AddGroup(_T("Built-In"), IDB_SHAPES_INFRA, 64, m_arInfraShapes);
pListBtnInfra->SetIconsInRow(4);
pListBtnInfra->EnableMenuResize();
pPanelDesign->Add(pListBtnInfra);

CRibbonListButton *pListBtnDev = new CRibbonListButton(ID_DESIGN_SHAPESDEV, _T("Development\ntd"), 35, -1, FALSE);
pListBtnDev->AddGroup(_T("Built-In"), IDB_SHAPES_DEV, 64, m_arInfraDev);
pListBtnDev->SetIconsInRow(4);
pListBtnDev->EnableMenuResize();
pPanelDesign->Add(pListBtnDev);

// Create "Debug" panel
CMFCRibbonPanel* pPanelDebug = pCategory->AddPanel(_T("Debug\nzd"), m_PanelImages.ExtractIcon(2));
pPanelDebug->Add(new CMFCRibbonButton(ID_DEBUG_DUMP_OBJECTS, _T("Dump Objects\nc"), 2));

CMFCRibbonButtonsGroup * apFontGroup = new CMFCRibbonButtonsGroup();
CMFCRibbonFontComboBox* pFontCombo = new CMFCRibbonFontComboBox(ID_FONT_FONT);
pFontCombo->SetWidth(55, TRUE); // Width in "floaty" mode
pFontCombo->SelectItem(10);
apFontGroup->AddButton(pFontCombo);

CMFCRibbonComboBox* pFontSizeCombo = new CMFCRibbonComboBox(ID_FONT_FONTSIZE, FALSE, 39);
pFontSizeCombo->AddItem(_T("8"));
pFontSizeCombo->AddItem(_T("9"));
pFontSizeCombo->AddItem(_T("10"));
pFontSizeCombo->AddItem(_T("11"));
pFontSizeCombo->AddItem(_T("12"));
pFontSizeCombo->AddItem(_T("14"));
pFontSizeCombo->AddItem(_T("16"));
pFontSizeCombo->AddItem(_T("18"));
pFontSizeCombo->AddItem(_T("20"));
pFontSizeCombo->AddItem(_T("22"));
pFontSizeCombo->AddItem(_T("24"));
pFontSizeCombo->AddItem(_T("26"));
pFontSizeCombo->AddItem(_T("28"));
pFontSizeCombo->AddItem(_T("36"));
pFontSizeCombo->AddItem(_T("48"));
pFontSizeCombo->AddItem(_T("72"));
pFontSizeCombo->SetWidth(20, TRUE); // Width in "floaty" mode
pFontSizeCombo->SelectItem(3);
apFontGroup->AddButton(pFontSizeCombo);

pPanelDebug->Add(apFontGroup);

// Create "Show/Hide" panel:
CMFCRibbonPanel* pPanelShow = pCategory->AddPanel(_T("Show/Hide\nzs"), m_PanelImages.ExtractIcon(4));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_FILE_VIEW, _T("Solution View\nc")));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_CLASS_VIEW, _T("Class View\nc")));
pPanelShow->Add(new CMFCRibbonCheckBox(ID_VIEW_PROPERTIES, _T("Properties View\np")));

// Create "Action" panel
CMFCRibbonPanel* pPanelAction = pCategory->AddPanel(_T("Action\nzd"), m_PanelImages.ExtractIcon(2));
pPanelAction->Add(new CMFCRibbonButton(ID_ACTION_REMOVE, _T("Remove\nc"), 12));
pPanelAction->Add(new CMFCRibbonButton(ID_ACTION_LOAD_MODULE, _T("Import .NET Module\nin"), 35));

// Create "Format" panel
CMFCRibbonPanel* pPanelFormat = pCategory->AddPanel(_T("Format and Style\nzd"), m_PanelImages.ExtractIcon(2));
CMFCRibbonColorButton * pBtnFillColor = new CMFCRibbonColorButton(ID_FORMAT_FILLCOLOR, _T("Fill Color\nsf"), FALSE, 1, -1);
pBtnFillColor->SetDefaultCommand(FALSE);
pBtnFillColor->EnableAutomaticButton(_T("&Automatic"), RGB(128, 128, 128));
pBtnFillColor->EnableOtherButton(_T("&More Fill Colors..."), _T("More Fill Colors"));
pBtnFillColor->SetColumns(10);
pBtnFillColor->SetColorBoxSize(CSize(17, 17));
pBtnFillColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnFillColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnFillColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pBtnFillColor->AddSubItem(new CMFCRibbonButton(ID_FORMAT_NOFILL, _T("&No Fill\nn"), -1));
pBtnFillColor->SetColor((COLORREF)-1);
pPanelFormat->Add(pBtnFillColor);

CMFCRibbonColorButton * pBtnLineColor = new CMFCRibbonColorButton(ID_FORMAT_LINECOLOR, _T("Line Color\nso"), FALSE, 3, -1);
pBtnLineColor->SetDefaultCommand(FALSE);
pBtnLineColor->EnableAutomaticButton(_T("&Automatic"), RGB(0, 0, 0));
pBtnLineColor->EnableOtherButton(_T("&More Line Colors..."), _T("More Line Colors"));
pBtnLineColor->SetColumns(10);
pBtnLineColor->SetColorBoxSize(CSize(17, 17));
pBtnLineColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnLineColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnLineColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pBtnLineColor->AddSubItem(new CMFCRibbonButton(ID_FORMAT_NOLINE, _T("&No Line\nn"), 2));
pBtnLineColor->SetColor((COLORREF)-1);
pPanelFormat->Add(pBtnLineColor);

CStringArray sa;
sa.Add(_T("1 pt"));
sa.Add(_T("2 pt"));
sa.Add(_T("3 pt"));
sa.Add(_T("4 pt"));
sa.Add(_T("5 pt"));
sa.Add(_T("6 pt"));
sa.Add(_T("7 pt"));

CRibbonListButton * pBtnLineWeight = new CRibbonListButton(ID_FORMAT_LINEWIDTH, _T("Line Width\nsw"), 4, -1, IDB_LINEWEIGHT, 96, sa);
pBtnLineWeight->AddSubItem(new CMFCRibbonButton(ID_FORMAT_LINEWIDTH_MORE, _T("More &Lines..."), 5, -1));
pBtnLineWeight->EnableMenuResize(TRUE, TRUE); // Vertical only
pPanelFormat->Add(pBtnLineWeight);

CMFCRibbonColorButton * pBtnPageColor = new CMFCRibbonColorButton(ID_FORMAT_PAGECOLOR, _T("Page Color\npo"), TRUE, -1, 26);
pBtnPageColor->SetDefaultCommand(FALSE);
pBtnPageColor->EnableAutomaticButton(_T("&Automatic"), RGB(0, 0, 0));
pBtnPageColor->EnableOtherButton(_T("&More Line Colors..."), _T("More Line Colors"));
pBtnPageColor->SetColumns(10);
pBtnPageColor->SetColorBoxSize(CSize(17, 17));
pBtnPageColor->AddColorsGroup(_T("Theme Colors"), m_lstMainColors);
pBtnPageColor->AddColorsGroup(_T(""), m_lstAdditionalColors, TRUE);
pBtnPageColor->AddColorsGroup(_T("Standard Colors"), m_lstStandardColors);
pPanelFormat->Add(pBtnPageColor);

pPanelFormat->Add(new CMFCRibbonButton(ID_FORMAT_ZOOM_IN, _T("Zoom In\ni"), -1));
pPanelFormat->Add(new CMFCRibbonButton(ID_FORMAT_ZOOM_OUT, _T("Zoom Out\no"), -1));
CMFCRibbonComboBox *pBtnZoom = new CMFCRibbonComboBox(ID_FORMAT_ZOOM, FALSE, 50, _T("Zoom: "), -1);
pBtnZoom->AddItem(_T("100 %"));
pBtnZoom->AddItem(_T("150 %"));
pBtnZoom->AddItem(_T("200 %"));
pBtnZoom->AddItem(_T("400 %"));
pBtnZoom->AddItem(_T("25 %"));
pBtnZoom->AddItem(_T("50 %"));
pBtnZoom->AddItem(_T("75 %"));
pBtnZoom->SelectItem(0);
pPanelFormat->Add(pBtnZoom);

// Create "Position" panel
CMFCRibbonPanel* pPanelPosition = pCategory->AddPanel(_T("Position\nzd"), m_PanelImages.ExtractIcon(2));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVETOFRONT, _T("Move to Front\nc"), -1, 22));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVEFORWARD, _T("Move Forward\nc"), -1, 24));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVEBACKWARD, _T("Move Backward\nc"), -1, 25));
pPanelPosition->Add(new CMFCRibbonButton(ID_POSITION_MOVETOBACK, _T("Move to Back\nc"), -1, 23));
}
<pre>

See more on codeplex here : https://ultrafluid.codeplex.com/SourceControl/latest#Modeler1/MainFrm.cpp

How to serialize a vector to an XML file using C++ Boost serialization

The Boost library provides a serialization library to serialize objects to XML or text stream. It is very simple to use. Here is my two class, one that contains a vector of shapes and the class of shapes.

//
// CShapeCollection
//
class CShapeCollection
{
public:
	CShapeCollection() {}
	~CShapeCollection() {}

private:
	friend class boost::serialization::access;

	template<class Archive>
	void save(Archive & ar, const unsigned int version) const
	{
		ar & BOOST_SERIALIZATION_NVP(m_shapes);
	}

	template<class Archive>
	void load(Archive & ar, const unsigned int version)
	{
		ar & BOOST_SERIALIZATION_NVP(m_shapes);
	}

    BOOST_SERIALIZATION_SPLIT_MEMBER()

public:
	vector<boost::shared_ptr<CSimpleShape> > m_shapes;
};

BOOST_CLASS_VERSION(CShapeCollection, 1)

//
// CSimpleShape
//
class CSimpleShape
{
public:
	CSimpleShape() {}
	~CSimpleShape() {}

private:
	friend class boost::serialization::access;
	template<class Archive>
	void save(Archive & ar, const unsigned int version) const
	{
		// ar & name;
		// ar & id;
		ar & BOOST_SERIALIZATION_NVP(m_name);
		ar & BOOST_SERIALIZATION_NVP(m_id);
		ar & BOOST_SERIALIZATION_NVP(m_rect);
		ar & BOOST_SERIALIZATION_NVP(m_type);
		ar & BOOST_SERIALIZATION_NVP(m_shapeType);
		ar & BOOST_SERIALIZATION_NVP(m_caption);
		ar & BOOST_SERIALIZATION_NVP(m_text);
		ar & BOOST_SERIALIZATION_NVP(m_x1);
		ar & BOOST_SERIALIZATION_NVP(m_y1);
		ar & BOOST_SERIALIZATION_NVP(m_x2);
		ar & BOOST_SERIALIZATION_NVP(m_y2);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillR);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillG);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillB);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineR);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineG);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineB);
		ar & BOOST_SERIALIZATION_NVP(m_bSolidColorFill);
		ar & BOOST_SERIALIZATION_NVP(m_bColorLine);
		ar & BOOST_SERIALIZATION_NVP(m_bColorFill);
	}

	template<class Archive>
	void load(Archive & ar, const unsigned int version)
	{
		// ar & name;
		// ar & id;
		ar & BOOST_SERIALIZATION_NVP(m_name);
		ar & BOOST_SERIALIZATION_NVP(m_id);
		ar & BOOST_SERIALIZATION_NVP(m_rect);
		ar & BOOST_SERIALIZATION_NVP(m_type);
		ar & BOOST_SERIALIZATION_NVP(m_shapeType);
		ar & BOOST_SERIALIZATION_NVP(m_caption);
		ar & BOOST_SERIALIZATION_NVP(m_text);
		ar & BOOST_SERIALIZATION_NVP(m_x1);
		ar & BOOST_SERIALIZATION_NVP(m_y1);
		ar & BOOST_SERIALIZATION_NVP(m_x2);
		ar & BOOST_SERIALIZATION_NVP(m_y2);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillR);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillG);
		ar & BOOST_SERIALIZATION_NVP(m_colorFillB);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineR);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineG);
		ar & BOOST_SERIALIZATION_NVP(m_colorLineB);
		ar & BOOST_SERIALIZATION_NVP(m_bSolidColorFill);
		ar & BOOST_SERIALIZATION_NVP(m_bColorLine);
		ar & BOOST_SERIALIZATION_NVP(m_bColorFill);
	}
    BOOST_SERIALIZATION_SPLIT_MEMBER()

public:
	string m_name;
	string m_id;
	string m_rect;
	long m_type;
	long m_shapeType;
	string m_caption;
	string m_text;
	long m_x1;
	long m_y1;
	long m_x2;
	long m_y2;
	int m_colorFillR;
	int m_colorFillG;
	int m_colorFillB;
	int m_colorLineR;
	int m_colorLineG;
	int m_colorLineB;
	bool m_bSolidColorFill;
	bool m_bColorLine;
	bool m_bColorFill;
};

BOOST_CLASS_VERSION(CSimpleShape, 1)

Now you have the data, you need to fill it and call the serialize to XML method… In my code, the real data of the application is the CElement. I have a vector of CElement but I need to transfer each element from CElement to SimpleShape witch is the XML container. It is a matter of separation. Then I call boost::archive::xml_oarchive… It is simple.

void CElementManager::Serialize_SaveAsXML(CModeler1View * pView)
{
	CFileDialog dlg(FALSE);
	if( dlg.DoModal() == IDCANCEL )
		return;

	CString strFileName = dlg.GetFileName();
	CString strPath = dlg.GetFolderPath();
	CString strFile;
	strFile.Format("%s\\%s", strPath, strFileName);
	std::string filename = (LPCTSTR)strFile;

	boost::shared_ptr<CShapeCollection> data(new CShapeCollection());

	for( vector<std::shared_ptr<CElement>>::iterator i = m_objects.m_objects.begin() ; i!=m_objects.m_objects.end() ; i++ )
	{
		std::shared_ptr<CElement> pElement = *i;
		boost::shared_ptr<CSimpleShape> pNewElement(new CSimpleShape());
		pNewElement->m_name = pElement->m_name;
		pNewElement->m_id = pElement->m_objectId;
		pNewElement->m_type = pElement->m_type;
		pNewElement->m_shapeType = pElement->m_shapeType;
		pNewElement->m_caption = pElement->m_caption;
		pNewElement->m_text = pElement->m_text;

		CPoint p1 = pElement->m_rect.TopLeft();
		CPoint p2 = pElement->m_rect.BottomRight();
		pNewElement->m_x1 = p1.x;
		pNewElement->m_y1 = p1.y;
		pNewElement->m_x2 = p2.x;
		pNewElement->m_y2 = p2.y;

		pNewElement->m_colorFillR = GetRValue(pElement->m_colorFill);
		pNewElement->m_colorFillG = GetGValue(pElement->m_colorFill);
		pNewElement->m_colorFillB = GetBValue(pElement->m_colorFill);
		pNewElement->m_colorLineR = GetRValue(pElement->m_colorLine);
		pNewElement->m_colorLineG = GetGValue(pElement->m_colorLine);
		pNewElement->m_colorLineB = GetBValue(pElement->m_colorLine);

		pNewElement->m_bSolidColorFill = pElement->m_bSolidColorFill;
		pNewElement->m_bColorLine = pElement->m_bColorLine;
		pNewElement->m_bColorFill = pElement->m_bColorFill;

		data->m_shapes.push_back(pNewElement);
	}

	// load an archive
	std::ofstream xofs(filename.c_str());
	boost::archive::xml_oarchive xoa(xofs);
	xoa << BOOST_SERIALIZATION_NVP(data);

}

Implementing a ribbon using C++ in native app

In my modeler, I have a Ribbon with pictures inside.

Ribbon_Infrastructure

To build it, you need some code.

        CRibbonListButton *pListBtnInfra = new CRibbonListButton(ID_DESIGN_SHAPESINFRA, _T("Infrastructure\nti"), 20, -1, FALSE);
	pListBtnInfra->AddGroup(_T("Built-In"), IDB_SHAPES_INFRA, 64, m_arInfraShapes);
	pListBtnInfra->SetIconsInRow(4);
	pListBtnInfra->EnableMenuResize();
	pPanelDesign->Add(pListBtnInfra);

The class CRibbonListButton  provides a simple way to load a full bitmap and display each part of it in a cell. IBD_SHAPES_INFRA is defined in the resource file as a PNG in res\ShapesInfra.png

ShapesInfra

To handle the click on the ribbon in your view, you just have to retrieve the ID of the clicked bitmap using CMFCRibbonGallery::GetLastSelectedItem().

void CModeler1View::OnModelingInfrastructure()
{
	// TODO: Add your command handler code here
	GetManager()->m_type = ElementType::type_shapes_infrastructure;
	int shapeId = CMFCRibbonGallery::GetLastSelectedItem(ID_DESIGN_SHAPESINFRA);
	GetManager()->m_shapeType = CShapeType::ToShapeType(OffsetShapes_Infrastructure + shapeId);

	//CString str;
	//str.Format("shapeId=%d m_shapeType=%d", shapeId, GetManager()->m_shapeType);
	//AfxMessageBox(str);
}

 

How to implement a ZoomIn & ZoomOut feature

When you think drawing objects on a window, you can think about GDI and its device context API. MFC provided a CDC class of that. But if you need transformation on your drawing objects, there is a better way wich is called GDI+. It provides a lot of API and classes to fill your need.

First, you construct a Graphics object from a device context. In your Draw handler, you just have to write this:

        // Initialize GDI+ graphics context
	Graphics graphics(pDC->m_hDC);

And you tell GDI+ to apply a zoom factor using the ScaleTransform() method:

        graphics.ScaleTransform(m_fZoomFactor, m_fZoomFactor);</pre>

All you have to do is to increment or decrement your float member zoom factor from ZoomIn and ZoomOut handler.

On the OnClick handler, you must be able to select your object with the mouse regardless of the zoom. You have to translate your pixel point to the rendering point that applies the scale transform operation. It is done using the ViewToManager routine call in the click handler:

void CElementManager::OnLButtonDown(CModeler1View* pView, UINT nFlags, const CPoint& cpoint)
{
	CPoint point = cpoint;
	ViewToManager(pView, point);
	m_lastPoint = point;

        ... 

void CElementManager::ManagerToView(CModeler1View * pView, CPoint & point)
{
	CClientDC dc(pView);
	Graphics graphics(dc.m_hDC);
	graphics.ScaleTransform(m_fZoomFactor, m_fZoomFactor);
	Point points[1] = {Point(point.x, point.y)};
	// Transform the points in the array from world to page coordinates.
	graphics.TransformPoints(
		CoordinateSpaceDevice, 
		CoordinateSpaceWorld, 
		points, 
		1);
	point.x = points[0].X;
	point.y = points[0].Y;
}

To find the whole source code to implement a zoomin & zoomout feature, consult my codeplex repository here: http://ultrafluid.codeplex.com/SourceControl/latest#Modeler1/ElementManager.cpp

TechDays 2014 in Paris

This year will be a remake of TechDays 2013. We will present with Loic J. from CAST a C++ session about C++ 11 and Visual C++ product.

Session information: http://www.microsoft.com/france/mstechdays/programmes/2014/fiche-session.aspx?ID=aa2b32fe-c4a0-4abd-94b2-c4ebaa13c235

We will cover some fundamentals of C++ 11 and always a good taste of demos and source code.