Sure! I have a debt to the ROOT community. I have never written a ROOT macro from scratch, so here’s my headers, Makefile, input file and code. If you have any improvements (I have not much experience neither with ROOT nor with c++) and if you want to make a macro out of my code, please go ahead!
LinkDef.h:
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class gui_maps+;
#endif
gui_maps.h:
#include "TGFrame.h"
class gui_maps : public TGMainFrame
{
private:
public:
gui_maps(const TGWindow *p, UInt_t w, UInt_t h, UInt_t options);
virtual ~gui_maps() {}
void store_xml(const char*);
void load_xml(const char*);
void HandleMenu(Int_t);
void GetVar();
void run_gui_maps();
ClassDef(gui_maps, 0)
};
Makefile:
include $(ROOTSYS)/test/Makefile.arch
SRCS := gui_maps.$(SrcSuf) gui_maps_Dict.$(SrcSuf)
OBJS := $(SRCS:.$(SrcSuf)=.$(ObjSuf)) gui_maps_Dict.$(ObjSuf)
EXE = GUI_MAPS$(ExeSuf)
PROGRAMS = $(EXE)
.SUFFIXES: .$(SrcSuf) .$(ObjSuf)
all: $(PROGRAMS)
$(EXE): $(OBJS)
$(LD) $(LDFLAGS) $^ $(ROOTGLIBS) -lXMLIO $(OutPutOpt)$@
@echo "$@ done"
gui_maps_Dict.cxx: gui_maps.h LinkDef.h
@echo "Generating dictionary $@..."
@rootcint -f $@ -c $^
clean:
rm -f *.o *.d *Dict.*
.$(SrcSuf).$(ObjSuf):
$(CXX) $(CXXFLAGS) $(EXTRAFLAGS) -c $<
xml/default.xml:
<?xml version="1.0"?>
<main>
<GraphPulse type="bool">true</GraphPulse>
<GraphTime type="bool">false</GraphTime>
<Acq type="string">26904</Acq>
<Path type="string">/myhome/GUI_MAPS</Path>
<PeakAlgorythm type="combo">1</PeakAlgorythm>
<SeparationLines type="combo">2</SeparationLines>
<TimeBin type="double">0.01</TimeBin>
<WindowLength type="int">120</WindowLength>
</main>
gui_maps.cpp:
#include "Riostream.h"
#include "gui_maps.h"
#include "TGNumberEntry.h"
#include "TGFrame.h"
#include "TGLabel.h"
#include "TApplication.h"
#include "TFrame.h"
#include "TXMLEngine.h"
#include "TGFileDialog.h"
#include "TGMenu.h"
#include "TGComboBox.h"
#include "TGToolBar.h"
#include "TGToolTip.h"
#include "TRootHelpDialog.h"
#include <stdlib.h>
#include <sstream>
#include <map>
map<string, bool> d_boo;
map<string, int> d_int;
map<string, int> d_com;
map<string, double> d_dbl;
map<string, string> d_str, typ_map;
map<TString, TGTextEntry*> d_txt;
map<TString, TGNumberEntry*> d_num;
map<TString, TGComboBox*> d_cmb;
map<TString, TGCheckButton*> d_ckb;
int jstr;
string homedir = getenv("HOME");
string gui_maps_dir = homedir + "/root/gui_maps";
string xml_dir = gui_maps_dir + "/xml/";
gui_maps *main_frame;
const char gHelpGUI_MAPS[] = "GUIs with maps, ask giovannitardini at yahoo.de";
enum EMyMessageTypes{
M_FILE_LOAD,
M_FILE_SAVE,
M_FILE_EXE,
M_FILE_EXIT,
M_HELP_ABOUT
};
const char *gui_maps_types[] = {
"xml files", "*.xml",
"All files", "*",
0 , 0
};
static ToolBarData_t gToolBarData[] ={
{ "bld_exit.png" , "Exit\tCtrl+Q" , kFALSE, M_FILE_EXIT, 0 },
{ "ed_execute.png", "Run GUI_MAPS\tCtrl+R" , kFALSE, M_FILE_EXE , 0 },
{ "bld_open.png" , "Load setup...\tCtrl+L" , kFALSE, M_FILE_LOAD, 0 },
{ "bld_save.png" , "Save setup as...\tCtrl+U", kFALSE, M_FILE_SAVE, 0 },
{ 0 , 0 , kFALSE, 0 , 0 }
};
void xml2dic(TXMLEngine* xml, XMLNodePointer_t node, Int_t level) {
XMLNodePointer_t child;
XMLAttrPointer_t attr = xml->GetFirstAttr(node);
const char* cvar = xml->GetNodeName(node);
const char* content = xml->GetNodeContent(node);
const char* att_nam;
const char* att_val;
string satt_val,satt_nam;
string svar = string(cvar);
string sval;
while (attr != 0){
att_nam = xml->GetAttrName(attr);
att_val = xml->GetAttrValue(attr);
attr = xml->GetNextAttr(attr);
satt_nam=string(att_nam);
satt_val=string(att_val);
typ_map[svar] = satt_val;
sval = string(content);
if (satt_val == "bool"){
if (sval == "true"){
d_boo[svar]=true;
}
else{
d_boo[svar]=false;
}
}
if (satt_val == "string"){
d_str[svar]=sval;
}
if (satt_val == "int"){
stringstream ss;
ss << sval;
ss >> d_int[svar];
}
if (satt_val == "combo"){
stringstream ss;
ss << sval;
ss >> d_com[svar];
}
if (satt_val == "double"){
stringstream ss;
ss << sval;
ss >> d_dbl[svar];
}
}
// display all child nodes
child = xml->GetChild(node);
while (child!=0){
xml2dic(xml, child, level+2);
child = xml->GetNext(child);
}
}
gui_maps::gui_maps( const TGWindow *p, UInt_t w, UInt_t h, UInt_t options) : TGMainFrame(p, w, h, options) {
int i,j;
// GUI objects
TString clbl;
TGLabel *wid_lbl;
TGLabel *str_lbl;
ULong_t ucolor;
TGFont *ufont;
TGGC *uGC;
TGHorizontalFrame *data_box = 0;
// GUI graphics
int const linspace=25,txt_wid=90,fld_wid=65,margin_hor=5;
int const fld_hgt=22,ndline=35,lbl_wid=85,txt_fld=165,side_len=320;
Int_t nline=ndline;
int spacing=8;
Int_t menu_h=28;
int remap[4] = {2,3,1,0};
// Menubar
TGMenuBar *fMenuBar;
TGPopupMenu *fMenuFile;
TGPopupMenu *fMenuHelp;
TGToolBar *fToolBar;
//=====================
// Menubar and toolbar
//=====================
SetCleanup(kDeepCleanup);
fMenuBar = new TGMenuBar(this, 0, 0, kHorizontalFrame|kRaisedFrame);
fMenuFile = new TGPopupMenu(gClient->GetRoot());
fToolBar = new TGToolBar(this, 0, 0, kHorizontalFrame|kRaisedFrame);
for (i = 0; gToolBarData[i].fPixmap; i++){
j=remap[i];
if (j == 0){
fMenuFile->AddSeparator();
}
fMenuFile->AddEntry( gToolBarData[j].fTipText, gToolBarData[j].fId, 0,
fClient->GetPicture(gToolBarData[j].fPixmap) );
TGPictureButton *pb = new TGPictureButton(fToolBar,
fClient->GetPicture(gToolBarData[i].fPixmap), gToolBarData[i].fId);
pb->SetToolTipText(gToolBarData[i].fTipText);
TGToolTip *tip = pb->GetToolTip();
tip->SetDelay(100);
fToolBar->AddButton(this, pb, spacing);
spacing = 0;
}
fMenuHelp = new TGPopupMenu(gClient->GetRoot());
fMenuHelp->AddEntry(" &About...", M_HELP_ABOUT, 0,gClient->GetPicture("about.xpm"));
fMenuBar->AddPopup(" &File", fMenuFile, new TGLayoutHints(kLHintsTop|kLHintsLeft));
fMenuBar->AddPopup(" &Help", fMenuHelp, new TGLayoutHints(kLHintsTop|kLHintsRight));
AddFrame(fMenuBar);
AddFrame(fToolBar);
fMenuBar->MoveResize(0,0,side_len,menu_h);
fToolBar->MoveResize(0,menu_h,side_len,menu_h);
fMenuFile->Connect("Activated(Int_t)", "gui_maps", this, "HandleMenu(Int_t)");
fToolBar ->Connect("Clicked(Int_t)", "gui_maps", this, "HandleMenu(Int_t)");
fMenuHelp->Connect("Activated(Int_t)", "gui_maps", this, "HandleMenu(Int_t)");
//==========
// GUI frame
//==========
SetLayoutBroken(kTRUE);
gClient->GetColorByName("#ccccaa",ucolor);
ufont = gClient->GetFont("-*-helvetica-medium-r-*-*-12-*-*-*-*-*-iso8859-1");
data_box = new TGHorizontalFrame(this,248,112,kHorizontalFrame,ucolor);
GCValues_t gval;
gval.fMask = kGCForeground | kGCBackground | kGCFillStyle | kGCFont | kGCGraphicsExposures;
gClient->GetColorByName("#000000",gval.fForeground);
gClient->GetColorByName("#c0c0c0",gval.fBackground);
gval.fFillStyle = kFillSolid;
gval.fFont = ufont->GetFontHandle();
gval.fGraphicsExposures = kFALSE;
uGC = gClient->GetGC(&gval, kTRUE);
gClient->GetColorByName("#ffff99",ucolor);
TGLabel *data_lbl = new TGLabel(data_box,"Data I/O files",TGLabel::GetDefaultGC()(),TGLabel::GetDefaultFontStruct(),kChildFrame,ucolor);
data_lbl->MoveResize(58,margin_hor,120,25);
// Example: Textentries
string in_str[] = {"Path","Acq","stop"};
for (jstr = 0; in_str[jstr] != "stop"; jstr++){
clbl=in_str[jstr];
str_lbl = new TGLabel(data_box,clbl,TGLabel::GetDefaultGC()(),TGLabel::GetDefaultFontStruct(),kChildFrame,ucolor);
d_txt[clbl] = new TGTextEntry(data_box, new TGTextBuffer(31),-1,uGC->GetGC(),ufont->GetFontStruct(),kSunkenFrame | kDoubleBorder | kOwnBackground);
d_txt[clbl]->SetName(clbl);
d_txt[clbl]->Connect("TextChanged(char*)", "gui_maps", this, "GetVar()");
str_lbl ->MoveResize(margin_hor ,nline,lbl_wid,fld_hgt);
d_txt[clbl]->MoveResize(margin_hor+lbl_wid,nline,txt_fld,fld_hgt);
nline += linspace;
}
// Example: Numberentries, int and double
string in_num[] = {"TimeBin","WindowLength","stop"};
for (jstr=0; in_num[jstr] != "stop"; jstr++){
clbl=in_num[jstr];
wid_lbl = new TGLabel(data_box,clbl,TGLabel::GetDefaultGC()(),TGLabel::GetDefaultFontStruct(),kChildFrame,ucolor);
d_num[clbl] = new TGNumberEntry(data_box, 0,11,-1,(TGNumberFormat::EStyle) 5);
d_num[clbl]->GetNumberEntry()->SetName(clbl);
d_num[clbl]->GetNumberEntry()->Connect("TextChanged(char*)", "gui_maps", this, "GetVar()");
wid_lbl ->MoveResize(margin_hor ,nline,txt_wid,fld_hgt);
d_num[clbl]->MoveResize(margin_hor+txt_wid,nline,fld_wid,fld_hgt);
nline += linspace;
}
// Example: Checkbuttons
string in_boo[] = {"GraphPulse","GraphTime","stop"};
for (jstr=0; in_boo[jstr] != "stop"; jstr++){
clbl=in_boo[jstr];
d_ckb[clbl] = new TGCheckButton(data_box, clbl);
d_ckb[clbl]->SetBackgroundColor(ucolor);
d_ckb[clbl]->SetName(clbl);
d_ckb[clbl]->Connect("Toggled(Bool_t)", "gui_maps", this, "GetVar()");
d_ckb[clbl]->MoveResize(margin_hor,nline,txt_wid,fld_hgt);
nline += linspace;
}
// Example: Comboboxes
string in_cmb[] = {"SeparationLines","PeakAlgorythm","stop"};
for (jstr=0; in_cmb[jstr] != "stop"; jstr++){
clbl=in_cmb[jstr];
wid_lbl = new TGLabel(data_box,clbl,TGLabel::GetDefaultGC()(),TGLabel::GetDefaultFontStruct(),kChildFrame,ucolor);
d_cmb[clbl] = new TGComboBox(data_box,-1,kHorizontalFrame | kSunkenFrame | kDoubleBorder | kOwnBackground);
d_cmb[clbl]->AddEntry("1",1);
d_cmb[clbl]->AddEntry("2",2);
wid_lbl ->MoveResize(margin_hor ,nline,txt_wid,fld_hgt);
d_cmb[clbl]->MoveResize(margin_hor+txt_wid,nline,fld_wid,fld_hgt);
data_box->AddFrame(d_cmb[clbl], new TGLayoutHints(kLHintsNormal,2,2,2,2));
d_cmb[clbl]->SetName(clbl);
d_cmb[clbl]->Connect("Selected(Int_t)", "gui_maps", this, "GetVar()");
AddFrame(data_box, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
nline += linspace;
}
data_box->SetLayoutBroken(kTRUE);
data_box->MoveResize(margin_hor,70,side_len,430);
//============
// MAIN frame
//============
AddInput(kKeyPressMask | kKeyReleaseMask);
MapSubwindows();
SetWindowName("GUI_MAPS");
MapWindow();
MoveResize(300,300,side_len,side_len);
string xmlfile = xml_dir+"default.xml";
const char* cname = xmlfile.c_str();
gui_maps::load_xml(cname);
}
void gui_maps::GetVar() {
// Updating the maps at every change in the GUI
TGNumberEntry *entry = (TGNumberEntry*)gTQSender;
string lbl=entry->GetName();
string stype=typ_map[lbl];
TString clbl;
clbl=lbl;
cout << clbl << " = ";
if (stype == "int"){
d_int[lbl]=d_num[clbl]->GetNumber();
cout << d_int[lbl];
}
if (stype == "double"){
d_dbl[lbl]=d_num[clbl]->GetNumber();
cout << d_dbl[lbl];
}
if (stype == "string"){
d_str[lbl]=d_txt[clbl]->GetText();
cout << d_str[lbl];
}
if (stype == "combo"){
d_com[lbl]=d_cmb[clbl]->GetSelected();
cout << d_com[lbl];
}
if (stype == "bool"){
d_boo[lbl]=d_ckb[clbl]->IsDown();
cout << d_boo[lbl];
}
cout << endl;
}
int main(int argc, char *argv[]) {
TApplication *theApp = new TApplication("gui_maps", &argc, argv);
main_frame = new gui_maps(gClient->GetRoot(),10,10,kMainFrame | kVerticalFrame);
theApp->Run();
}
void gui_maps::HandleMenu(Int_t menu_id) {
// Handle menu events
TRootHelpDialog *hd;
char * cxml = new char[xml_dir.length()];
strcpy(cxml,xml_dir.c_str());
TGFileInfo fi;
fi.fFileTypes = gui_maps_types;
fi.fIniDir = cxml;
switch (menu_id) {
case M_FILE_EXIT:
CloseWindow();
gApplication->Terminate(0);
break;
case M_FILE_LOAD:
new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
cxml = fi.fIniDir;
gui_maps::load_xml(fi.fFilename);
break;
case M_FILE_SAVE:
new TGFileDialog(gClient->GetRoot(), this, kFDSave, &fi);
cxml = fi.fIniDir;
gui_maps::store_xml(fi.fFilename);
break;
case M_FILE_EXE:
gui_maps::run_gui_maps();
break;
case M_HELP_ABOUT:
hd = new TRootHelpDialog(this, "About GUI_MAPS...", 550, 250);
hd->SetText(gHelpGUI_MAPS);
hd->Popup();
break;
}
}
void dic2xml(XMLNodePointer_t mainnode) {
// Converts map into a 1-level xml object
map<string, bool> :: iterator biter;
map<string, string>:: iterator siter;
map<string, int> :: iterator iiter;
map<string, double>:: iterator diter;
string lbl;
bool bval;
int val;
double dval;
TString clbl;
TString cval;
TXMLEngine* xml=0;
XMLNodePointer_t xnode;
for (biter = d_boo.begin(); biter != d_boo.end(); ++biter){
clbl=biter->first;
bval=biter->second;
if (bval){
xnode = xml->NewChild(mainnode, 0, clbl, "true");
}
else{
xnode = xml->NewChild(mainnode, 0, clbl, "false");
}
xml->NewAttr(xnode, 0, "type","bool");
}
for (siter = d_str.begin(); siter != d_str.end(); ++siter){
clbl=siter->first;
cval=siter->second;
xnode = xml->NewChild(mainnode, 0, clbl,cval);
xml->NewAttr(xnode, 0, "type","string");
}
for (iiter = d_int.begin(); iiter != d_int.end(); ++iiter){
clbl=iiter->first;
val =iiter->second;
stringstream ss;
ss << val;
cval = ss.str();
xnode = xml->NewChild(mainnode, 0, clbl, cval);
xml->NewAttr(xnode, 0, "type","int");
}
for (iiter = d_com.begin(); iiter != d_com.end(); ++iiter){
clbl=iiter->first;
val =iiter->second;
stringstream ss;
ss << val;
cval = ss.str();
xnode = xml->NewChild(mainnode, 0, clbl, cval);
xml->NewAttr(xnode, 0, "type","combo");
}
for (diter = d_dbl.begin(); diter != d_dbl.end(); ++diter){
clbl=diter->first;
dval=diter->second;
stringstream ss;
ss << dval;
cval = ss.str();
xnode = xml->NewChild(mainnode, 0, clbl, cval);
xml->NewAttr(xnode, 0, "type","double");
}
}
void gui_maps::load_xml(const char* cname) {
// Reads in a xml file, it translates it into the working maps and fills the
// proper GNU entries
TString clbl;
TString cval;
bool bval;
int val;
double dval;
map<string, bool> :: iterator biter;
map<string, string>:: iterator siter;
map<string, int> :: iterator iiter;
map<string, double>:: iterator diter;
TXMLEngine* xml=0;
XMLNodePointer_t mainnode = 0;
XMLDocPointer_t xmldoc = 0;
xmldoc = xml->ParseFile(cname);
if (xmldoc==0){
delete xml;
return;
}
mainnode = xml->DocGetRootElement(xmldoc);
xml2dic(xml, mainnode, 1);
cout << "Loading " << cname << endl;
for (biter = d_boo.begin(); biter != d_boo.end(); ++biter){
clbl=biter->first;
bval=biter->second;
if (bval){
d_ckb[clbl]->SetState(kButtonDown);
}
else{
d_ckb[clbl]->SetState(kButtonUp);
}
}
for (siter = d_str.begin(); siter != d_str.end(); ++siter){
clbl=siter->first;
cval=siter->second;
d_txt[clbl]->SetText(cval);
}
for (iiter = d_int.begin(); iiter != d_int.end(); ++iiter){
clbl=iiter->first;
val =iiter->second;
d_num[clbl]->SetIntNumber(Long_t(val));
}
for (iiter = d_com.begin(); iiter != d_com.end(); ++iiter){
clbl=iiter->first;
val =iiter->second;
d_cmb[clbl]->Select(Long_t(val));
}
for (diter = d_dbl.begin(); diter != d_dbl.end(); ++diter){
clbl=diter->first;
dval=diter->second;
d_num[clbl]->SetNumber(dval);
}
xml->FreeDoc(xmldoc);
delete xml;
}
void gui_maps::store_xml(const char* cname) {
// Stores the current GUI entries values into a xml file
// via the maps, that are always up-to-date
TXMLEngine* xml=0;
XMLDocPointer_t xmldoc = 0;
XMLNodePointer_t mainnode = 0;
mainnode = xml->NewChild(0, 0, "main");
cout << "Storing " << cname << endl;
dic2xml(mainnode);
xmldoc = xml->NewDoc();
xml->DocSetRootElement(xmldoc, mainnode);
xml->SaveDoc(xmldoc, cname);
xml->FreeDoc(xmldoc);
delete xml;
}
void gui_maps::run_gui_maps() {
cout << "Running my prog" << endl;
}