File indexing completed on 2025-08-03 08:20:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include "Poms.h"
0023
0024 #include <onlmon/OnlMonClient.h>
0025
0026 #include <GuiTypes.h> // for kHorizontalFrame, kRaisedFrame
0027 #include <TCanvas.h>
0028 #include <TGButton.h>
0029 #include <TGClient.h> // for TGClient, gClient
0030 #include <TGLayout.h> // for TGLayoutHints, kLHintsTop, kLHintsE...
0031 #include <TGMenu.h>
0032 #include <TGMsgBox.h>
0033 #include <TGString.h> // for TGHotString
0034 #include <TList.h> // for TList
0035 #include <TROOT.h>
0036 #include <TSystem.h>
0037 #include <TSeqCollection.h> // for TSeqCollection
0038 #include <TString.h> // for TString
0039 #include <WidgetMessageTypes.h> // for GET_MSG, GET_SUBMSG, kCM_BUTTON
0040
0041 #include <cmath>
0042 #include <cstdlib>
0043 #include <cstring> // for strlen
0044 #include <iostream>
0045
0046 const int SUBSYSTEM_ACTION_ID_BEGIN = 10001;
0047
0048
0049 const char* pomsFileTypes[] =
0050 {
0051 "PHENIX raw data files", "*.prdf",
0052 "All files", "*",
0053 nullptr, nullptr};
0054
0055
0056
0057
0058
0059
0060 PomsMainFrame* PomsMainFrame::_instance = nullptr;
0061
0062 PomsMainFrame* PomsMainFrame::Instance()
0063 {
0064 if (!_instance)
0065 _instance = new PomsMainFrame(gClient->GetRoot(), 1, 1);
0066
0067 return _instance;
0068 }
0069
0070 PomsMainFrame::PomsMainFrame(const TGWindow* p, UInt_t w, UInt_t h)
0071 : TGMainFrame(p, w, h)
0072 , _rootHorizPad(10)
0073 , _rootVertPad(0)
0074 , _windowPad(20)
0075 {
0076
0077
0078 std::cout << POMS_VER << "PomsMainFrame constructor called..." << std::endl;
0079
0080
0081 if (getenv("ONLMON_MACROS"))
0082 {
0083 _macroPath = getenv("ONLMON_MACROS");
0084 }
0085 else
0086 {
0087 std::cout << "Environment variable ONLMON_MACROS not set, using current dir" << std::endl;
0088 _macroPath = "./";
0089 }
0090
0091 TGFrame* rootWin = (TGFrame*) gClient->GetRoot();
0092 _rootWidth = rootWin->GetDefaultWidth();
0093 if (_rootWidth > 2000)
0094 {
0095 _rootWidth = _rootWidth / 2;
0096 }
0097 _rootHeight = rootWin->GetDefaultHeight();
0098
0099 std::cout << POMS_VER << "Screen Width: " << _rootWidth << std::endl;
0100 std::cout << POMS_VER << "Screen Height: " << _rootHeight << std::endl;
0101
0102 TGLayoutHints* menuLayout = new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0);
0103
0104
0105
0106
0107
0108 _menuFile = new TGPopupMenu(gClient->GetRoot());
0109 _menuFile->AddEntry("&Exit", M_FILE_EXIT);
0110 _menuFile->Associate(this);
0111 _menuBar = new TGMenuBar(this, 1, 1, kHorizontalFrame | kRaisedFrame);
0112 _menuBar->AddPopup("&File", _menuFile, menuLayout);
0113
0114 _menuWindow = new TGPopupMenu(gClient->GetRoot());
0115 _menuWindow->AddEntry("&Align Control Bar to Right", M_WINDOW_ALIGNRIGHT);
0116 _menuWindow->AddEntry("&Tile All", M_WINDOW_TILEALL);
0117 _menuWindow->Associate(this);
0118 _menuBar->AddPopup("&Window", _menuWindow, menuLayout);
0119 _menuBar->AddPopup("&DontpushThis", _menuFile, menuLayout);
0120 AddFrame(_menuBar, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX,
0121 0, 0, 1, 1));
0122
0123
0124 SetWindowName("POMS: PHENIX Online Monitoring System");
0125 _shutter = nullptr;
0126 }
0127
0128 void PomsMainFrame::SetMacroPath(const char* path)
0129 {
0130 _macroPath = path;
0131 }
0132
0133 void PomsMainFrame::Draw()
0134 {
0135 OnlMonClient* cl = OnlMonClient::instance();
0136
0137 std::cout << POMS_VER << "Attempting Build of PomsMainFrame..." << std::endl;
0138
0139
0140 if (_shutter)
0141 {
0142 delete _shutter;
0143 }
0144 _shutter = BuildShutter();
0145 AddFrame(_shutter, new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY));
0146
0147 MapSubwindows();
0148 MapWindow();
0149 AlignRight();
0150 int xsize = cl->GetDisplaySizeX();
0151 if (xsize > 2000)
0152 {
0153 xsize = xsize / 2;
0154 }
0155 int ysize = cl->GetDisplaySizeY();
0156 xsize -= (_shutter->GetDefaultWidth()) + 30;
0157 ysize -= 100;
0158 cl->SetDisplaySizeX(xsize);
0159 cl->SetDisplaySizeY(ysize);
0160 }
0161
0162 PomsMainFrame::~PomsMainFrame()
0163 {
0164
0165
0166 delete _closeButton;
0167 delete _menuBar;
0168 delete _menuFile;
0169 delete _shutter;
0170 delete _menuWindow;
0171
0172
0173
0174 _instance = nullptr;
0175 }
0176
0177 void PomsMainFrame::CloseWindow()
0178 {
0179
0180 TGMainFrame::CloseWindow();
0181 std::cout << "\n\n"
0182 << std::endl;
0183 OnlMonClient *cl = OnlMonClient::instance();
0184 delete cl;
0185 gSystem->Exit(0);
0186
0187 }
0188
0189 Bool_t PomsMainFrame::ProcessMessage(Long_t msg, Long_t parm1, Long_t )
0190 {
0191
0192
0193 int status = 1;
0194
0195 #ifdef DEBUG
0196
0197
0198 std::cout << "Msg = " << msg << std::endl
0199 << "GET_MSG = " << GET_MSG(msg) << std::endl
0200 << "SUB_MSG = " << GET_SUBMSG(msg) << std::endl
0201 << "parm1 = " << parm1 << std::endl
0202 << "parm2 = " << parm2 << std::endl;
0203
0204 #endif
0205
0206 switch (GET_MSG(msg))
0207 {
0208 case kC_COMMAND:
0209
0210 switch (GET_SUBMSG(msg))
0211 {
0212 case kCM_MENU:
0213 switch (parm1)
0214 {
0215 case M_FILE_EXIT:
0216 CloseWindow();
0217 break;
0218
0219 case M_WINDOW_ALIGNRIGHT:
0220 AlignRight();
0221 break;
0222 case M_WINDOW_TILEALL:
0223 TileAllCanvases();
0224 break;
0225
0226 default:
0227 break;
0228 }
0229 break;
0230
0231 case kCM_BUTTON:
0232 switch (parm1)
0233 {
0234 default:
0235 HandleButtonPoms(parm1);
0236 break;
0237 }
0238 }
0239 break;
0240 }
0241
0242 int retval;
0243 if (status != 1)
0244 {
0245 new TGMsgBox(gClient->GetRoot(), this,
0246 POMS_VER, "General error in executing widget handler!",
0247 kMBIconStop, kMBOk, &retval);
0248 }
0249
0250 return kTRUE;
0251 }
0252
0253 int PomsMainFrame::HandleButtonPoms(Long_t parm1)
0254 {
0255
0256 if (parm1 > (SUBSYSTEM_ACTION_ID_BEGIN - 1))
0257 {
0258 SubSystemAction* action = SubSystemAction::FindById(parm1);
0259
0260 if (!action)
0261 return -1;
0262
0263 return action->Execute();
0264 }
0265
0266 return -1;
0267 }
0268
0269 SubSystem* PomsMainFrame::RegisterSubSystem(const char* name, const char* prefix,
0270 int addDefaultActions, int loadLibrary)
0271 {
0272 SubSystem* sub = nullptr;
0273
0274 try
0275 {
0276 sub = new SubSystem(name, prefix, loadLibrary);
0277
0278 if (addDefaultActions != 0)
0279 sub->AddDefaultActions();
0280
0281 _subSystemList.push_back(sub);
0282 std::cout << POMS_VER << "SubSystem " << name << " added..." << std::endl;
0283 }
0284 catch (char* str)
0285 {
0286 std::cout << POMS_VER << "Unable to add subsystem " << name << "!" << std::endl;
0287 std::cout << "\t" << str << std::endl;
0288 delete str;
0289 delete sub;
0290 }
0291 return sub;
0292 }
0293
0294 SubSystem* PomsMainFrame::RegisterSubSystem(SubSystem* subSystem)
0295 {
0296 _subSystemList.push_back(subSystem);
0297 std::cout << POMS_VER << "SubSystem " << subSystem->GetName() << " added..." << std::endl;
0298 return subSystem;
0299 }
0300
0301 TGShutter* PomsMainFrame::BuildShutter()
0302 {
0303 TGShutter* shutter = new TGShutter(this);
0304 TGShutterItem* shutterItem;
0305 TGCompositeFrame* container;
0306 TGTextButton* button;
0307 TGLayoutHints* layout;
0308
0309 SubSystemList::iterator subSystem;
0310 SubSystemActionList* actionList;
0311 SubSystemActionList::iterator action;
0312 int shutterItemId = 101;
0313
0314 std::cout << POMS_VER << "Building SubSystem Shutter..." << std::endl;
0315
0316
0317 layout = new TGLayoutHints(kLHintsExpandX | kLHintsTop, 5, 5, 0, 0);
0318
0319 for (subSystem = _subSystemList.begin(); subSystem != _subSystemList.end(); ++subSystem)
0320 {
0321 actionList = (*subSystem)->GetActions();
0322 action = actionList->begin();
0323
0324
0325 if (action != actionList->end())
0326 {
0327 std::cout << POMS_VER << "\tAdding " << (*subSystem)->GetName() << " to shutter" << std::endl;
0328
0329 shutterItem = new TGShutterItem(shutter,
0330 new TGHotString((*subSystem)->GetName().c_str()),
0331 shutterItemId++);
0332 container = (TGCompositeFrame*) shutterItem->GetContainer();
0333
0334 for (; action != actionList->end(); ++action)
0335 {
0336 std::cout << POMS_VER << "\t\tAdding \"" << (*action)->GetDescription() << "\" button..." << std::endl;
0337 button = new TGTextButton(container,
0338 (*action)->GetDescription().c_str(),
0339 (*action)->GetId());
0340 button->SetTextColor(0xCC00FF);
0341 container->AddFrame(button, layout);
0342 button->Associate(this);
0343 }
0344 shutter->AddItem(shutterItem);
0345 }
0346 }
0347 return shutter;
0348 }
0349
0350 void PomsMainFrame::AlignRight()
0351 {
0352 Int_t x = (_rootWidth - GetDefaultWidth() - _rootHorizPad);
0353 Int_t y = _rootVertPad;
0354
0355 UInt_t width = GetDefaultWidth();
0356 UInt_t height = _rootHeight - (2 * _rootVertPad) - 90;
0357
0358 Resize(width, height);
0359 Move(x, y);
0360 }
0361
0362 void PomsMainFrame::TileCanvases(TList* canvasList)
0363 {
0364 if (!canvasList)
0365 {
0366 std::cout << POMS_VER << "cannot tile canvases, canvas list empty!" << std::endl;
0367 return;
0368 }
0369 AlignRight();
0370
0371 TCanvas* canvas = (TCanvas*) canvasList->First();
0372 int windowCount = canvasList->LastIndex() + 1;
0373
0374 int windowCountHoriz = (int) ceil(sqrt((double) windowCount));
0375 int windowCountVert = (int) floor(sqrt((double) windowCount));
0376
0377 int i;
0378 int j;
0379
0380 int currX = _rootHorizPad;
0381
0382 int width = (int) ((_rootWidth - (2 * _rootHorizPad) -
0383 (windowCountHoriz * _windowPad) - GetDefaultWidth()) /
0384 windowCountHoriz);
0385 int height = (int) ((_rootHeight - (2 * _rootVertPad) - (windowCountVert * _windowPad)) / windowCountVert);
0386
0387 for (i = 0; i < windowCountHoriz; i++)
0388 {
0389
0390 int currY = _rootVertPad;
0391 currX += (width * i) + _windowPad;
0392
0393 for (j = 0; j < windowCountVert; j++)
0394 {
0395 currY += (height * j) + _windowPad;
0396
0397 if (canvas)
0398 {
0399 canvas->SetWindowSize(width, height);
0400 canvas->SetWindowPosition(currX, currY);
0401
0402 canvas = (TCanvas*) canvasList->After(canvas);
0403 }
0404 }
0405 }
0406 }
0407
0408 void PomsMainFrame::CascadeCanvases(TList* )
0409 {
0410 }
0411
0412 void PomsMainFrame::TileAllCanvases()
0413 {
0414
0415 SubSystemList::iterator subSystem;
0416 TList* canvasList = new TList();
0417
0418 for (subSystem = _subSystemList.begin(); subSystem != _subSystemList.end(); ++subSystem)
0419 {
0420 canvasList->AddAll((*subSystem)->GetCanvases());
0421 (*subSystem)->ShowCanvases();
0422 }
0423 TileCanvases(canvasList);
0424
0425 delete canvasList;
0426 }
0427
0428
0429
0430
0431
0432 SubSystem::SubSystem(const char* name, const char* prefix, int loadLibrary)
0433 : _name(name)
0434 , _prefix(prefix)
0435 , _canvasList(nullptr)
0436 , _initialized(0)
0437 {
0438 std::string macroPath;
0439
0440 if ((strlen(name) < 1) || (strlen(prefix) < 1))
0441 {
0442 const char* error = "ERROR: name and prefix must not be null!";
0443 throw error;
0444 }
0445
0446 if (loadLibrary)
0447 {
0448 macroPath = PomsMainFrame::Instance()->GetMacroPath();
0449 if (macroPath.size() == 0)
0450 macroPath = ".";
0451 gROOT->LoadMacro((macroPath + "/run_" + _prefix + "_client.C").c_str());
0452 }
0453 }
0454
0455 SubSystem::~SubSystem()
0456 {
0457 delete _canvasList;
0458 }
0459
0460 TList* SubSystem::GetCanvases(int forceReQuery)
0461 {
0462
0463 if (_canvasList && !forceReQuery)
0464 return _canvasList;
0465
0466 delete _canvasList;
0467
0468 TSeqCollection* allCanvases = gROOT->GetListOfCanvases();
0469 TCanvas* canvas = (TCanvas*) allCanvases->First();
0470 TString* prefix = new TString(_prefix.c_str());
0471
0472 prefix->ToLower();
0473
0474 while (canvas)
0475 {
0476 TString* canvasName = new TString(canvas->GetName());
0477 canvasName->ToLower();
0478
0479 if (canvasName->Contains(*prefix))
0480 {
0481
0482 if (!_canvasList)
0483 {
0484
0485 _canvasList = new TList();
0486 }
0487 _canvasList->Add(canvas);
0488 }
0489
0490 delete canvasName;
0491 canvas = (TCanvas*) allCanvases->After(canvas);
0492 }
0493
0494 delete prefix;
0495
0496 if (!_canvasList)
0497 std::cout << POMS_VER << "Canvas list empty for subsystem " << _name << "!" << std::endl;
0498
0499 return _canvasList;
0500 }
0501
0502 void SubSystem::PrintCanvasList()
0503 {
0504 TList* canvasList;
0505 TCanvas* canvas;
0506
0507 if (!(canvasList = GetCanvases()))
0508 return;
0509
0510 std::cout << POMS_VER << "Querying subsystem " << _name << " for canvases:" << std::endl;
0511 canvas = (TCanvas*) canvasList->First();
0512 while (canvas)
0513 {
0514 std::cout << "\t" << canvas->GetName() << std::endl;
0515 canvas = (TCanvas*) canvasList->After(canvas);
0516 }
0517 std::cout << "End of Canvas List" << std::endl;
0518 return;
0519 }
0520
0521 void SubSystem::ShowCanvases()
0522 {
0523 TList* canvasList;
0524 TCanvas* canvas;
0525
0526 if (!(canvasList = GetCanvases()))
0527 return;
0528
0529 canvas = (TCanvas*) canvasList->First();
0530 while (canvas)
0531 {
0532 canvas->Show();
0533 canvas = (TCanvas*) canvasList->After(canvas);
0534 }
0535 return;
0536 }
0537
0538 SubSystemAction* SubSystem::AddAction(const char* cmd, const char* description)
0539 {
0540 SubSystemAction* action = nullptr;
0541
0542 try
0543 {
0544 action = new SubSystemAction(this, cmd, description);
0545 _actions.push_back(action);
0546
0547 std::cout << POMS_VER << "Action " << cmd << " added to " << _name << "..." << std::endl;
0548 }
0549 catch (char* str)
0550 {
0551 std::cout << POMS_VER << "Unable to add action " << cmd << "!" << std::endl;
0552 std::cout << "\t" << str << std::endl;
0553 delete str;
0554 delete action;
0555 }
0556 return action;
0557 }
0558
0559 SubSystemAction* SubSystem::AddAction(const std::string& cmd, const std::string& description)
0560 {
0561 return AddAction(cmd.c_str(), description.c_str());
0562 }
0563
0564 SubSystemAction* SubSystem::AddAction(SubSystemAction* action)
0565 {
0566 _actions.push_back(action);
0567
0568 std::cout << POMS_VER << "Action \"" << action->GetDescription() << "\" added to " << _name << "..." << std::endl;
0569 return action;
0570 }
0571
0572 void SubSystem::AddDefaultActions()
0573 {
0574 std::cout << POMS_VER << "Add default actions to subsystem " << _name << "..." << std::endl;
0575
0576
0577 AddAction(new SubSystemActionDraw(this));
0578 AddAction(new SubSystemActionDrawPS(this));
0579
0580
0581
0582
0583
0584
0585
0586 }
0587
0588 void SubSystem::TileCanvases()
0589 {
0590 PomsMainFrame* pmf = PomsMainFrame::Instance();
0591 pmf->TileCanvases(GetCanvases());
0592 ShowCanvases();
0593 }
0594
0595 void SubSystem::CascadeCanvases()
0596 {
0597 PomsMainFrame* pmf = PomsMainFrame::Instance();
0598 pmf->CascadeCanvases(GetCanvases());
0599 ShowCanvases();
0600 }
0601
0602
0603
0604
0605
0606 int SubSystemAction::_nextId = SUBSYSTEM_ACTION_ID_BEGIN;
0607 SubSystemActionMap SubSystemAction::_map;
0608
0609 SubSystemAction::SubSystemAction(SubSystem* parent)
0610 : _running(false)
0611 , _parent(parent)
0612 {
0613 if (!parent)
0614 {
0615 const char* error = "ERROR: Action must have parent!";
0616 throw error;
0617 }
0618
0619 _id = NextId();
0620 _map[_id];
0621 }
0622
0623 SubSystemAction::SubSystemAction(SubSystem* parent, const char* description)
0624 : _running(false)
0625 , _parent(parent)
0626 , _description(description)
0627 {
0628 if (!parent)
0629 {
0630 const char* error = "ERROR: Action must have parent!";
0631 throw error;
0632 }
0633
0634 _id = NextId();
0635 _map[_id] = this;
0636 }
0637
0638 SubSystemAction::SubSystemAction(SubSystem* parent, const char* cmd, const char* description)
0639 : _running(false)
0640 , _parent(parent)
0641 , _cmd(cmd)
0642 , _description(description)
0643 {
0644 if (!parent || (strlen(cmd) < 1))
0645 {
0646 const char* error = "ERROR: Action must have parent and command string!";
0647 throw error;
0648 }
0649
0650 _id = NextId();
0651 _map[_id] = this;
0652 }
0653
0654 SubSystemAction::~SubSystemAction()
0655 {
0656 _map[_id] = nullptr;
0657 }
0658
0659 int SubSystemAction::Execute()
0660 {
0661 if (_running)
0662 return 0;
0663
0664 _running = true;
0665 if (!_parent->isInitialized())
0666 {
0667 gROOT->ProcessLine((_parent->GetPrefix() + "DrawInit(1)").c_str());
0668 _parent->setInitialized(1);
0669 }
0670
0671 TSeqCollection* allCanvases = gROOT->GetListOfCanvases();
0672 TCanvas* canvas = nullptr;
0673 while ((canvas = (TCanvas*) allCanvases->First()))
0674 {
0675 std::cout << "Deleting Canvas " << canvas->GetName() << std::endl;
0676 delete canvas;
0677 }
0678 gROOT->ProcessLine(_cmd.c_str());
0679 _running = false;
0680 return 0;
0681 }
0682
0683
0684
0685
0686
0687 SubSystemActionDraw::SubSystemActionDraw(SubSystem* parent)
0688 : SubSystemAction(parent, "Draw")
0689 {
0690 }
0691
0692 int SubSystemActionDraw::Execute()
0693 {
0694 if (_running)
0695 return 0;
0696
0697 _running = true;
0698
0699 if (!_parent->isInitialized())
0700 {
0701 gROOT->ProcessLine((_parent->GetPrefix() + "DrawInit(1)").c_str());
0702 _parent->setInitialized(1);
0703 }
0704
0705 TSeqCollection* allCanvases = gROOT->GetListOfCanvases();
0706 TCanvas* canvas = nullptr;
0707 while ((canvas = (TCanvas*) allCanvases->First()))
0708 {
0709 std::cout << "Deleting Canvas " << canvas->GetName() << std::endl;
0710 delete canvas;
0711 }
0712 gROOT->ProcessLine((_parent->GetPrefix() + "Draw()").c_str());
0713 _running = false;
0714 return 0;
0715 }
0716
0717
0718
0719
0720
0721 SubSystemActionSavePlot::SubSystemActionSavePlot(SubSystem* parent)
0722 : SubSystemAction(parent, "Save Plots")
0723 {
0724 }
0725
0726 int SubSystemActionSavePlot::Execute()
0727 {
0728 if (_running)
0729 return 0;
0730
0731 _running = true;
0732 gROOT->ProcessLine((_parent->GetPrefix() + "SavePlot()").c_str());
0733 _running = false;
0734 return 0;
0735 }
0736
0737
0738
0739
0740
0741 SubSystemActionDrawPS::SubSystemActionDrawPS(SubSystem* parent)
0742 : SubSystemAction(parent, "Save Postscript")
0743 {
0744 }
0745
0746 int SubSystemActionDrawPS::Execute()
0747 {
0748 if (_running)
0749 return 0;
0750
0751 _running = true;
0752 gROOT->ProcessLine((_parent->GetPrefix() + "PS()").c_str());
0753 _running = false;
0754 return 0;
0755 }
0756
0757
0758
0759
0760
0761 SubSystemActionDrawHtml::SubSystemActionDrawHtml(SubSystem* parent)
0762 : SubSystemAction(parent, "Save to HTML")
0763 {
0764 }
0765
0766 int SubSystemActionDrawHtml::Execute()
0767 {
0768 if (_running)
0769 return 0;
0770
0771 _running = true;
0772 gROOT->ProcessLine((_parent->GetPrefix() + "Html()").c_str());
0773 _running = false;
0774 return 0;
0775 }
0776
0777
0778
0779
0780
0781 SubSystemActionShowCanvases::SubSystemActionShowCanvases(SubSystem* parent)
0782 : SubSystemAction(parent, "Show Canvases")
0783 {
0784 }
0785
0786 int SubSystemActionShowCanvases::Execute()
0787 {
0788 if (_running)
0789 return 0;
0790
0791 _running = true;
0792 _parent->ShowCanvases();
0793 _running = false;
0794 return 0;
0795 }
0796
0797
0798
0799
0800
0801 SubSystemActionTileCanvases::SubSystemActionTileCanvases(SubSystem* parent)
0802 : SubSystemAction(parent, "Tile Canvases")
0803 {
0804 }
0805
0806 int SubSystemActionTileCanvases::Execute()
0807 {
0808 if (_running)
0809 return 0;
0810
0811 _running = true;
0812 _parent->TileCanvases();
0813 _running = false;
0814 return 0;
0815 }
0816
0817
0818
0819
0820
0821 ColorShutterItem::ColorShutterItem(const ULong_t bgColor, const TGWindow* p, TGHotString* s,
0822 Int_t id, UInt_t options)
0823 : TGShutterItem(p, s, id, options)
0824 {
0825 fButton->ChangeBackground(bgColor);
0826 }