Tag Archives: MFC

Download UltraFluid modeler

You can download my application here:

http://www.windowscpp.com/Appz/UltraFluid_Modeler.zip

In the archive there are 2 main folders: bin and images. I have also created a shortcut. Adjust the shortcut to start the app located in bin but place the working directory on the upper folder.

I have a little bug on displaying images by setting the current folder. It will be fixed sooner.

To run the application, you must have vcredist from VS2015. These dll are not distributed in the zip archive.

ultrafluid_modeler_2

Updating Scintilla open-source project and Naughter’s wrappers and Boost 1.63

When I have updated Scintilla’s wrappers written by Naughter, I encountered compilation errors…
This the MFC class view that operates with the scintilla control. I need to update that class too. But first of all, I need to update Boost. Current version is 1.63. Just compile it with bjam. Classic stuff. Result is in stage\lib folder.

boost_stage_lib_163

For the moment I use Boost only for serialization stuff for XML stuff.

modeler1_saveasxml

Here is a XML file:

modeler1_data_xml

Boost serialization is not easy because it is designed that data has to be read by a Boost app…

Using open-source libraries for MyModeler C++ project

I will make some enhancements to my modeler project (http://ultrafluid.codeplex.com). I have moved to Visual Studio online.

image001

MyModeler

My project use three open-source projects:

– Scintilla (http://www.scintilla.org/)

– MFC Naughter classes to encapsulate Scintilla edit control with MFC (http://www.naughter.com/scintilla.html)

– Boost (http://www.boost.org/)

My project was primary built in the 2012′. It was an idea to make my daughter Lisa able to place elements with the mouse.
It is a family project. It was also an free-time occupation when I was consultant for the “Banque de France” to build Architecture diagrams.
The initial goal of the project is to build diagrams with individual shapes elements. These elements contains properties and everything is store in a database.
Then, it is possible to make requests to find things. For the moment, I have no database. I need to implement that part of the software.

First surprise when I rebuilt the project with the latest version of Scintilla, the Naughter classes produced C++ compilation errors.
I needed to get the latest classes but also make some minor corrections (hide the code of 2 methods).
For boost, I have a version 1.59 on my computer and I have no evidence to jump to the latest version because I just use serialization and XML stuff which belong to a very stable library : serialization.

I rebuilt the project and it just works. The project updated to MSVC140 build tools with Visual Studio 2015.
This is the magic of C++ : it works along all theses years… But my open-source libraries has evolved and most of the time, getting an updated version can bring some changes.
In my case, the Naughter MFC classes depends on Scintilla project so the GET operation must assure that the 2 projects are synced.

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

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);
}

 

Compiling MFC from command line using NMAKE

One interesting point using Visual C++ 2010 samples is contained in the MFC folder. You can build mfc samples using a makefile using this command: nmake -a -f makefile. The makefile file just contains your obj files, and then the RC part. Then you #include mfcsamps.mak and that’s all.

Sample:

PROJ=MODELER1
OBJS=AppInit.obj CalendarBar.obj ChildFrm.obj ClassView.obj \
Data.obj \
DrawingContext.obj DrawingElements.obj \
Element.obj ElementContainer.obj ElementFactory.obj ElementManager.obj  \
FileView.obj MainFrm.obj Modeler1.obj Modeler1Doc.obj  \
Modeler1SourceView.obj Modeler1View.obj OutputWnd.obj PropertiesWnd.obj RibbonListButton.obj SourceCodeView.obj TabbedView.obj \
ScintillaCtrl.obj ScintillaDocView.obj

USES_OLE=1

!include <mfcsamps.mak>

# Update the resource if necessary
Modeler1.res: Modeler1.rc resource.h
    rc $(rcflags) $(rcvars) -r -fo Modeler1.res Modeler1.rc

The project is named Modeler1 and the first part of the makefile contains the obj files. You take your cpp files and you write them using the obj extension. Next, the RC part is dedicated for resources.

The MFCSAMPS.MAK file is include into Microsoft Visual Studio\VC\ATLMFC\INCLUDE folder.