Eclipse SUMO - Simulation of Urban MObility
GNEPythonToolDialog.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // Dialog for tools
19 /****************************************************************************/
20 
22 #include <netedit/GNEViewNet.h>
23 #include <netedit/GNEViewParent.h>
27 
28 #include "GNEPythonToolDialog.h"
29 
30 #define MARGIN 4
31 #define MAXNUMCOLUMNS 4
32 #define NUMROWSBYCOLUMN 20
33 
34 // ===========================================================================
35 // FOX callback mapping
36 // ===========================================================================
37 
38 FXDEFMAP(GNEPythonToolDialog) GNEPythonToolDialogMap[] = {
39  FXMAPFUNC(SEL_CLOSE, 0, GNEPythonToolDialog::onCmdCancel),
41  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_SAVE, GNEPythonToolDialog::onCmdSave),
43  FXMAPFUNC(SEL_COMMAND, MID_CHOOSEN_LOAD, GNEPythonToolDialog::onCmdLoad),
45  FXMAPFUNC(SEL_COMMAND, MID_GNE_BUTTON_RUN, GNEPythonToolDialog::onCmdRun),
49 };
50 
51 // Object implementation
52 FXIMPLEMENT(GNEPythonToolDialog, FXDialogBox, GNEPythonToolDialogMap, ARRAYNUMBER(GNEPythonToolDialogMap))
53 
54 // ============================================-===============================
55 // member method definitions
56 // ===========================================================================
57 
59  FXDialogBox(GNEApp->getApp(), "Tool", GUIDesignAuxiliarDialogBoxResizable),
60  myGNEApp(GNEApp) {
61  // set icon
63  // create main content frame
64  auto verticalContentFrame = new FXVerticalFrame(this, GUIDesignContentsFrame);
65  // create options
66  auto horizontalOptionsFrame = new FXHorizontalFrame(verticalContentFrame, GUIDesignHorizontalFrameNoPadding);
67  // build options
68  myShowToolTipsMenu = new MFXCheckableButton(false, horizontalOptionsFrame,
69  GNEApp->getStaticTooltipMenu(), (std::string("\t") + TL("Toggle Menu Tooltips") + std::string("\t") + TL("Toggles whether tooltips in the menu shall be shown.")).c_str(),
71  auto saveFile = new MFXButtonTooltip(horizontalOptionsFrame, GNEApp->getStaticTooltipMenu(), TL("Save toolcfg"),
73  saveFile->setTipText(TL("Save file with tool configuration"));
74  auto loadFile = new MFXButtonTooltip(horizontalOptionsFrame, GNEApp->getStaticTooltipMenu(), TL("Load toolcfg"),
76  loadFile->setTipText(TL("Load file with tool configuration"));
77  mySortedCheckButton = new FXCheckButton(horizontalOptionsFrame, TL("Sorted by name"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);
78  myGroupedCheckButton = new FXCheckButton(horizontalOptionsFrame, TL("Grouped by categories"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);
79  // add separators
80  new FXSeparator(verticalContentFrame);
81  // Create scroll frame for content rows
82  auto contentScrollWindow = new FXScrollWindow(verticalContentFrame, GUIDesignScrollWindow);
83  auto horizontalRowFrames = new FXHorizontalFrame(contentScrollWindow, LAYOUT_FILL_X | LAYOUT_FILL_Y | PACK_UNIFORM_WIDTH);
84  myArgumentFrameLeft = new FXVerticalFrame(horizontalRowFrames, GUIDesignAuxiliarFrame);
85  myArgumentFrameRight = new FXVerticalFrame(horizontalRowFrames, GUIDesignAuxiliarFrame);
86  // add separator
87  new FXSeparator(verticalContentFrame);
88  // create buttons centered
89  auto horizontalButtonsFrame = new FXHorizontalFrame(verticalContentFrame, GUIDesignHorizontalFrame);
90  auto blueLabel = new FXLabel(horizontalButtonsFrame, TL("Blue options are mandatory"), nullptr, GUIDesignLabelFixed(200));
91  blueLabel->setTextColor(FXRGB(0, 0, 255));
92  new FXHorizontalFrame(horizontalButtonsFrame, GUIDesignAuxiliarHorizontalFrame);
93  GUIDesigns::buildFXButton(horizontalButtonsFrame, TL("Run"), "", TL("run python tool"),
95  GUIDesigns::buildFXButton(horizontalButtonsFrame, TL("Close"), "", TL("close tool dialog"),
97  GUIDesigns::buildFXButton(horizontalButtonsFrame, TL("Reset"), "", TL("reset to default values"),
99  new FXLabel(horizontalButtonsFrame, "", nullptr, GUIDesignLabelFixed(200));
100  new FXHorizontalFrame(horizontalButtonsFrame, GUIDesignAuxiliarHorizontalFrame);
101 }
102 
103 
105 
106 
107 void
109  // set tool
110  myPythonTool = tool;
111  // set title
112  setTitle(myPythonTool->getToolName().c_str());
113  // reset checkboxes
114  mySortedCheckButton->setCheck(FALSE);
115  myGroupedCheckButton->setCheck(TRUE);
116  // set myShowToolTipsMenu
117  myShowToolTipsMenu->setChecked(getApp()->reg().readIntEntry("gui", "menuToolTips", 0) != 1);
118  // set current values in options (like current folders and similar)
120  // build arguments
121  buildArguments(false, true);
122  // get maximum height
123  const int maximumHeight = myArgumentFrameLeft->numChildren() * GUIDesignHeight + 120;
124  // resize
125  resize(1024, maximumHeight <= 768 ? maximumHeight : 768);
126  // show dialog
127  FXDialogBox::show(PLACEMENT_SCREEN);
128  // refresh APP
129  getApp()->refresh();
130 }
131 
132 
135  return myGNEApp;
136 }
137 
138 
139 const GNEPythonTool*
141  return myPythonTool;
142 }
143 
144 
145 long
146 GNEPythonToolDialog::onCmdShowToolTipsMenu(FXObject*, FXSelector, void*) {
147  // toggle check
149  if (myGNEApp->getViewNet()) {
152  }
153  // enable/disable static tooltip
155  // save in registry
156  getApp()->reg().writeIntEntry("gui", "menuToolTips", myShowToolTipsMenu->amChecked() ? 0 : 1);
157  update();
158 
159  return 1;
160 }
161 
162 
163 long
164 GNEPythonToolDialog::onCmdSave(FXObject*, FXSelector, void*) {
165  // open save dialog
166  const std::string file = GNEApplicationWindowHelper::openOptionFileDialog(this, true);
167  // check file
168  if (file.size() > 0) {
170  }
171  return 1;
172 }
173 
174 
175 long
176 GNEPythonToolDialog::onCmdLoad(FXObject*, FXSelector, void*) {
177  // open file dialog
178  const std::string file = GNEApplicationWindowHelper::openOptionFileDialog(this, false);
179  // check file
180  if ((file.size() > 0) && myPythonTool->loadConfiguration(file)) {
181  // rebuild arguments
182  buildArguments((mySortedCheckButton->getCheck() == TRUE), (myGroupedCheckButton->getCheck() == TRUE));
183  }
184  return 1;
185 }
186 
187 
188 long
189 GNEPythonToolDialog::onCmdSetVisualization(FXObject*, FXSelector, void*) {
190  // rebuild arguments
191  buildArguments((mySortedCheckButton->getCheck() == TRUE), (myGroupedCheckButton->getCheck() == TRUE));
192  return 1;
193 }
194 
195 
196 long
197 GNEPythonToolDialog::onCmdRun(FXObject*, FXSelector, void*) {
198  // hide dialog
199  hide();
200  // run tool
201  return myGNEApp->tryHandle(myPythonTool->getMenuCommand(), FXSEL(SEL_COMMAND, MID_GNE_RUNPYTHONTOOL), nullptr);
202 }
203 
204 
205 long
206 GNEPythonToolDialog::onCmdCancel(FXObject*, FXSelector, void*) {
207  // hide dialog
208  hide();
209  return 1;
210 }
211 
212 
213 long
214 GNEPythonToolDialog::onCmdReset(FXObject*, FXSelector, void*) {
215  // iterate over all arguments and reset values
216  for (const auto& argument : myArguments) {
217  argument->reset();
218  }
219  return 1;
220 }
221 
222 
223 long
224 GNEPythonToolDialog::onUpdRequiredAttributes(FXObject* sender, FXSelector, void*) {
225  // iterate over all arguments and check if required attribute is set
226  for (const auto& argument : myArguments) {
227  if (argument->requiredAttributeSet() == false) {
228  return sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), nullptr);
229  }
230  }
231  return sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), nullptr);
232 }
233 
234 
236  std::string(category) {
237 }
238 
239 
240 void
241 GNEPythonToolDialog::CategoryOptions::addOption(const std::string& name, Option* option) {
242  myOptions.push_back(std::make_pair(name, option));
243 }
244 
245 
246 const std::vector<std::pair<std::string, Option*> >&
248  return myOptions;
249 }
250 
251 
252 void
254  // just sort vector with options
255  std::sort(myOptions.begin(), myOptions.end());
256 }
257 
258 
260  myGNEApp(nullptr) {
261 }
262 
263 
264 void
265 GNEPythonToolDialog::buildArguments(bool sortByName, bool groupedByCategories) {
266  // clear arguments and categories
267  for (const auto& argument : myArguments) {
268  delete argument;
269  }
270  for (const auto& category : myCategories) {
271  delete category;
272  }
273  myArguments.clear();
274  myCategories.clear();
275  // get argument sorted by name and grouped by categories
276  auto categoryOptions = groupedByCategories ? getOptionsByCategories(myPythonTool->getToolsOptions()) : getOptions(myPythonTool->getToolsOptions());
277  // calculate number of arguments
278  int numArguments = 0;
279  for (auto& categoryOption : categoryOptions) {
280  numArguments += (int)categoryOption.getOptions().size() + 1;
281  }
282  const int halfNumArguments = numArguments / 2;
283  // declare counter for number of inserted arguments
284  int numInsertedArguments = 0;
285  // iterate over category options
286  for (auto& categoryOption : categoryOptions) {
287  // get argument frame
288  auto argumentFrame = (numInsertedArguments < halfNumArguments) ? myArgumentFrameLeft : myArgumentFrameRight;
289  // add category
290  if (categoryOption.size() > 0) {
291  myCategories.push_back(new GNEPythonToolDialogElements::Category(argumentFrame, categoryOption));
292  numInsertedArguments++;
293  }
294  // check if sort by name
295  if (sortByName) {
296  categoryOption.sortByName();
297  }
298  // add options
299  for (const auto& option : categoryOption.getOptions()) {
300  // get argument frame (again)
301  argumentFrame = (numInsertedArguments < halfNumArguments) ? myArgumentFrameLeft : myArgumentFrameRight;
302  // continue depending of type
303  if (option.second->isInteger()) {
304  myArguments.push_back(new GNEPythonToolDialogElements::IntArgument(this, argumentFrame, option.first, option.second));
305  } else if (option.second->isFloat()) {
306  myArguments.push_back(new GNEPythonToolDialogElements::FloatArgument(this, argumentFrame, option.first, option.second));
307  } else if (option.second->isBool()) {
308  myArguments.push_back(new GNEPythonToolDialogElements::BoolArgument(this, argumentFrame, option.first, option.second));
309  } else if (option.second->isFileName()) {
310  myArguments.push_back(new GNEPythonToolDialogElements::FileNameArgument(this, argumentFrame, option.first, option.second));
311  } else if (option.second->isNetwork()) {
312  myArguments.push_back(new GNEPythonToolDialogElements::NetworkArgument(this, argumentFrame, option.first, option.second));
313  } else if (option.second->isAdditional()) {
314  myArguments.push_back(new GNEPythonToolDialogElements::AdditionalArgument(this, argumentFrame, option.first, option.second));
315  } else if (option.second->isRoute()) {
316  myArguments.push_back(new GNEPythonToolDialogElements::RouteArgument(this, argumentFrame, option.first, option.second));
317  } else if (option.second->isData()) {
318  myArguments.push_back(new GNEPythonToolDialogElements::DataArgument(this, argumentFrame, option.first, option.second));
319  } else if (option.second->isSumoConfig()) {
320  myArguments.push_back(new GNEPythonToolDialogElements::SumoConfigArgument(this, argumentFrame, option.first, option.second));
321  } else if (option.second->isEdge()) {
322  myArguments.push_back(new GNEPythonToolDialogElements::EdgeArgument(this, argumentFrame, option.first, option.second));
323  } else if (option.second->isEdgeVector()) {
324  myArguments.push_back(new GNEPythonToolDialogElements::EdgeVectorArgument(this, argumentFrame, option.first, option.second));
325  } else {
326  myArguments.push_back(new GNEPythonToolDialogElements::StringArgument(this, argumentFrame, option.first, option.second));
327  }
328  numInsertedArguments++;
329  }
330  }
331  // adjust parameter column (call always after create elements)
333 }
334 
335 
336 void
338  int maximumWidth = 0;
339  // iterate over all arguments and find the maximum width
340  for (const auto& argument : myArguments) {
341  const auto label = argument->getParameterLabel();
342  const int columnWidth = label->getFont()->getTextWidth(label->getText().text(), label->getText().length() + MARGIN);
343  if (columnWidth > maximumWidth) {
344  maximumWidth = columnWidth;
345  }
346  }
347  // set maximum width for all parameter labels
348  for (const auto& argument : myArguments) {
349  argument->getParameterLabel()->setWidth(maximumWidth);
350  }
351 }
352 
353 
354 std::vector<GNEPythonToolDialog::CategoryOptions>
356  // use a vector with only one empty category to reuse code of buildArguments
357  std::vector<GNEPythonToolDialog::CategoryOptions> result = {GNEPythonToolDialog::CategoryOptions("")};
358  // add all options to result
359  for (const auto& option : optionsCont) {
360  result.front().addOption(option.first, option.second);
361  }
362  return result;
363 }
364 
365 
366 std::vector<GNEPythonToolDialog::CategoryOptions>
368  // declare vector with common categories
369  const std::vector<std::string> commonCategories = {"input", "output", "processing", "time"};
370  // fill categories
371  std::vector<std::string> categories = commonCategories;
372  for (const auto& option : optionsCont) {
373  if (std::find(categories.begin(), categories.end(), option.second->getSubTopic()) == categories.end()) {
374  categories.push_back(option.second->getSubTopic());
375  }
376  }
377  // declare vector of category options and fill
378  std::vector<GNEPythonToolDialog::CategoryOptions> result;
379  for (const auto& category : categories) {
380  result.push_back(GNEPythonToolDialog::CategoryOptions(category));
381  }
382  // fill result with options
383  for (const auto& option : optionsCont) {
384  auto category = std::find(result.begin(), result.end(), option.second->getSubTopic());
385  // add option in category
386  category->addOption(option.first, option.second);
387  }
388  // drop empty categories
389  auto it = result.begin();
390  while (it != result.end()) {
391  if (it->getOptions().empty()) {
392  it = result.erase(it);
393  } else {
394  it++;
395  }
396  }
397  return result;
398 }
399 
400 
401 int
403  const int column = (int)myArguments.size() / NUMROWSBYCOLUMN;
404  return (column < MAXNUMCOLUMNS) ? column : (MAXNUMCOLUMNS - 1);
405 }
406 
407 
408 FXVerticalFrame*
410  return myArgumentFrameLeft;
411 }
412 
413 
414 FXVerticalFrame*
416  return myArgumentFrameRight;
417 }
418 
419 /****************************************************************************/
#define MAXNUMCOLUMNS
FXDEFMAP(GNEPythonToolDialog) GNEPythonToolDialogMap[]
#define MARGIN
#define NUMROWSBYCOLUMN
@ MID_GNE_SET_ATTRIBUTE
attribute edited
Definition: GUIAppEnum.h:935
@ MID_GNE_BUTTON_RUN
run button
Definition: GUIAppEnum.h:1413
@ MID_CHOOSEN_SAVE
Save set.
Definition: GUIAppEnum.h:603
@ MID_GNE_BUTTON_CANCEL
cancel button
Definition: GUIAppEnum.h:1399
@ MID_GNE_BUTTON_RESET
reset button
Definition: GUIAppEnum.h:1401
@ MID_GNE_RUNPYTHONTOOL
run python
Definition: GUIAppEnum.h:757
@ MID_SHOWTOOLTIPS_MENU
Show tool tips in menus - button.
Definition: GUIAppEnum.h:387
@ MID_CHOOSEN_LOAD
Load set.
Definition: GUIAppEnum.h:601
#define GUIDesignScrollWindow
design for scroll windows extended over Y and y
Definition: GUIDesigns.h:381
#define GUIDesignLabelFixed(width)
label, icon before text, text centered and custom width
Definition: GUIDesigns.h:252
#define GUIDesignButtonAccept
Accept Button.
Definition: GUIDesigns.h:162
#define GUIDesignButtonCancel
Cancel Button.
Definition: GUIDesigns.h:168
#define GUIDesignContentsFrame
design for the main content frame of every frame/dialog with padding and spacing
Definition: GUIDesigns.h:393
#define GUIDesignAuxiliarHorizontalFrame
design for auxiliar (Without borders) horizontal frame used to pack another frames
Definition: GUIDesigns.h:405
#define GUIDesignButtonConfiguration
Configuration Button.
Definition: GUIDesigns.h:165
#define GUIDesignMFXCheckableButtonSquare
Definition: GUIDesigns.h:143
#define GUIDesignAuxiliarDialogBoxResizable
design for standard dialog box (for example, about dialog)
Definition: GUIDesigns.h:614
#define GUIDesignCheckButton
checkButton placed in left position
Definition: GUIDesigns.h:198
#define GUIDesignButtonReset
Reset Button.
Definition: GUIDesigns.h:171
#define GUIDesignAuxiliarFrame
design for auxiliar (Without borders) frame extended in all directions
Definition: GUIDesigns.h:396
#define GUIDesignHorizontalFrameNoPadding
Horizontal frame extended over frame parent without padding and spacing.
Definition: GUIDesigns.h:337
#define GUIDesignHorizontalFrame
Horizontal frame extended over frame parent with padding and spacing.
Definition: GUIDesigns.h:334
@ SHOWTOOLTIPS_MENU
@ OPEN
open icons
@ SAVE
save icons
#define TL(string)
Definition: MsgHandler.h:315
int GUIDesignHeight
the default size for GUI elements
Definition: StdDefs.cpp:35
The main window of Netedit.
GNEViewNet * getViewNet()
get pointer to viewNet
internal class used for sorting options by categories
void addOption(const std::string &name, Option *option)
add option
const std::vector< std::pair< std::string, Option * > > & getOptions() const
get options
Dialog for python tool dialog.
std::vector< CategoryOptions > getOptionsByCategories(OptionsCont &optionsCont) const
get options sorted by category
FXVerticalFrame * myArgumentFrameRight
argument frame right
long onCmdCancel(FXObject *, FXSelector, void *)
event after press cancel button
GNEPythonTool * myPythonTool
python tool
void adjustParameterColumn()
adjust parameter column
int getNumRowColums() const
get number of row colums
GNEPythonToolDialog()
FOX needs this.
long onCmdLoad(FXObject *, FXSelector, void *)
load options
std::vector< GNEPythonToolDialogElements::Argument * > myArguments
list of arguments sorted by categories
GNEApplicationWindow * myGNEApp
pointer to GNEApplicationWindow
std::vector< GNEPythonToolDialogElements::Category * > myCategories
list of categories
long onCmdShowToolTipsMenu(FXObject *, FXSelector, void *)
enable/disable show toolTip
GNEApplicationWindow * getGNEApplicationWindow() const
get pointer to GNEApplicationWindow
long onCmdRun(FXObject *, FXSelector, void *)
event after press run button
MFXCheckableButton * myShowToolTipsMenu
menu for tooltips menu
std::vector< GNEPythonToolDialog::CategoryOptions > getOptions(OptionsCont &optionsCont) const
get options
FXVerticalFrame * getArgumentFrameLeft() const
get argument frame left
long onUpdRequiredAttributes(FXObject *sender, FXSelector, void *)
event for check if required attributes was set
FXCheckButton * mySortedCheckButton
check button to enable/diasble sorting
long onCmdSetVisualization(FXObject *, FXSelector, void *)
set visualization (sorting and grouping)
FXVerticalFrame * getArgumentFrameRight() const
get argument frame right
long onCmdReset(FXObject *, FXSelector, void *)
event after press reset button
FXVerticalFrame * myArgumentFrameLeft
argument frame left
const GNEPythonTool * getPythonTool() const
get python tool
long onCmdSave(FXObject *, FXSelector, void *)
save options
void buildArguments(bool sortByName, bool groupedByCategories)
build arguments
FXCheckButton * myGroupedCheckButton
check button to enable/diasble grouping
void openDialog(GNEPythonTool *tool)
open dialog
void saveConfiguration(const std::string &file) const
save configuration
bool loadConfiguration(const std::string &file)
load configuration
virtual void setCurrentValues()
set current values (used for set values like current folder and similar)
const std::string & getToolName() const
get tool name
FXMenuCommand * getMenuCommand() const
get menu command
OptionsCont & getToolsOptions()
get tools options
GNEViewParent * getViewParent() const
get the net object
static FXButton * buildFXButton(FXComposite *p, const std::string &text, const std::string &tip, const std::string &help, FXIcon *ic, FXObject *tgt, FXSelector sel, FXuint opts=BUTTON_NORMAL, FXint x=0, FXint y=0, FXint w=0, FXint h=0, FXint pl=DEFAULT_PAD, FXint pr=DEFAULT_PAD, FXint pt=DEFAULT_PAD, FXint pb=DEFAULT_PAD)
build button
Definition: GUIDesigns.cpp:128
MFXCheckableButton * getShowToolTipsMenu() const
get menu for tooltips menu
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
MFXStaticToolTip * getStaticTooltipMenu() const
get static toolTip for menus
bool amChecked() const
check if this MFXCheckableButton is checked
void setChecked(bool val, const bool inform=false)
check or uncheck this MFXCheckableButton
void enableStaticToolTip(const bool value)
enable/disable static tooltip
A class representing a single program option.
Definition: Option.h:72
A storage for options typed value containers)
Definition: OptionsCont.h:89
Definition: json.hpp:4471
static std::string openOptionFileDialog(FXWindow *window, bool save)
open option dialog