Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2025 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>
28
29#include "GNEPythonToolDialog.h"
30
31// ===========================================================================
32// Defines
33// ===========================================================================
34
35#define MARGIN 4
36#define MAXNUMCOLUMNS 4
37#define NUMROWSBYCOLUMN 20
38
39// ===========================================================================
40// FOX callback mapping
41// ===========================================================================
42
53
54// Object implementation
55FXIMPLEMENT(GNEPythonToolDialog, GNEDialog, GNEPythonToolDialogMap, ARRAYNUMBER(GNEPythonToolDialogMap))
56
57// ============================================-===============================
58// member method definitions
59// ===========================================================================
60
62 GNEDialog(applicationWindow, TL("Tool"), GUIIcon::TOOL_PYTHON, DialogType::PYTHON,
63 GNEDialog::Buttons::RUN_CANCEL_RESET, OpenType::MODAL, ResizeMode::RESIZABLE) {
64 // create options
65 auto horizontalOptionsFrame = new FXHorizontalFrame(myContentFrame, GUIDesignHorizontalFrameNoPadding);
66 // build options
67 myShowToolTipsMenu = new MFXCheckableButton(false, horizontalOptionsFrame,
68 applicationWindow->getStaticTooltipMenu(), (std::string("\t") + TL("Toggle Menu Tooltips") + std::string("\t") + TL("Toggles whether tooltips in the menu shall be shown.")).c_str(),
70 auto saveFile = new MFXButtonTooltip(horizontalOptionsFrame, applicationWindow->getStaticTooltipMenu(), TL("Save toolcfg"),
72 saveFile->setTipText(TL("Save file with tool configuration"));
73 auto loadFile = new MFXButtonTooltip(horizontalOptionsFrame, applicationWindow->getStaticTooltipMenu(), TL("Load toolcfg"),
75 loadFile->setTipText(TL("Load file with tool configuration"));
76 mySortedCheckButton = new FXCheckButton(horizontalOptionsFrame, TL("Sorted by name"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);
77 myGroupedCheckButton = new FXCheckButton(horizontalOptionsFrame, TL("Grouped by categories"), this, MID_GNE_SET_ATTRIBUTE, GUIDesignCheckButton);
78 // add separators
79 new FXSeparator(myContentFrame);
80 // Create scroll frame for content rows
81 auto contentScrollWindow = new FXScrollWindow(myContentFrame, GUIDesignScrollWindow);
82 auto horizontalRowFrames = new FXHorizontalFrame(contentScrollWindow, LAYOUT_FILL_X | LAYOUT_FILL_Y | PACK_UNIFORM_WIDTH);
83 myArgumentFrameLeft = new FXVerticalFrame(horizontalRowFrames, GUIDesignAuxiliarFrame);
84 myArgumentFrameRight = new FXVerticalFrame(horizontalRowFrames, GUIDesignAuxiliarFrame);
85 // set tool
86 myPythonTool = tool;
87 // set title
88 setTitle(myPythonTool->getToolName().c_str());
89 // reset checkboxes
90 mySortedCheckButton->setCheck(FALSE);
91 myGroupedCheckButton->setCheck(TRUE);
92 // set myShowToolTipsMenu
93 myShowToolTipsMenu->setChecked(getApp()->reg().readIntEntry("gui", "menuToolTips", 0) != 1);
94 // set current values in options (like current folders and similar)
95 myPythonTool->setCurrentValues();
96 // build arguments
97 buildArguments(false, true);
98 // get maximum height
99 const int maximumHeight = myArgumentFrameLeft->numChildren() * GUIDesignHeight + 120;
100 // resize
101 resize(1024, maximumHeight <= 768 ? maximumHeight : 768);
102 // open dialog
103 openDialog();
104}
105
106
108
109
110void
112 // nothing to do
113}
114
115
116const GNEPythonTool*
120
121
122long
123GNEPythonToolDialog::onCmdShowToolTipsMenu(FXObject*, FXSelector, void*) {
124 // toggle check
129 }
130 // enable/disable static tooltip
132 // save in registry
133 getApp()->reg().writeIntEntry("gui", "menuToolTips", myShowToolTipsMenu->amChecked() ? 0 : 1);
134 update();
135
136 return 1;
137}
138
139
140long
141GNEPythonToolDialog::onCmdSave(FXObject*, FXSelector, void*) {
142 // open save dialog
143 const auto optionsFileDialog = GNEFileDialog(this, myApplicationWindow,
144 TL("options file"),
148 // check file
149 if (optionsFileDialog.getResult() == GNEDialog::Result::ACCEPT) {
150 myPythonTool->saveConfiguration(optionsFileDialog.getFilename());
151 }
152 return 1;
153}
154
155
156long
157GNEPythonToolDialog::onCmdLoad(FXObject*, FXSelector, void*) {
158 // open file dialog
159 const auto optionsFileDialog = GNEFileDialog(this, myApplicationWindow,
160 TL("options file"),
164 // check file
165 if ((optionsFileDialog.getResult() == GNEDialog::Result::ACCEPT) && myPythonTool->loadConfiguration(optionsFileDialog.getFilename())) {
166 // rebuild arguments
167 buildArguments((mySortedCheckButton->getCheck() == TRUE), (myGroupedCheckButton->getCheck() == TRUE));
168 }
169 return 1;
170}
171
172
173long
174GNEPythonToolDialog::onCmdSetVisualization(FXObject*, FXSelector, void*) {
175 // rebuild arguments
176 buildArguments((mySortedCheckButton->getCheck() == TRUE), (myGroupedCheckButton->getCheck() == TRUE));
177 return 1;
178}
179
180
181long
182GNEPythonToolDialog::onCmdRun(FXObject*, FXSelector, void*) {
183 // hide dialog
185 // run tool
186 return myApplicationWindow->tryHandle(myPythonTool->getMenuCommand(), FXSEL(SEL_COMMAND, MID_GNE_RUNPYTHONTOOL), nullptr);
187}
188
189
190long
191GNEPythonToolDialog::onCmdReset(FXObject*, FXSelector, void*) {
192 // iterate over all arguments and reset values
193 for (const auto& argument : myArguments) {
194 argument->reset();
195 }
196 return 1;
197}
198
199
200long
201GNEPythonToolDialog::onUpdRequiredAttributes(FXObject* sender, FXSelector, void*) {
202 // iterate over all arguments and check if required attribute is set
203 for (const auto& argument : myArguments) {
204 if (argument->requiredAttributeSet() == false) {
205 return sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), nullptr);
206 }
207 }
208 return sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), nullptr);
209}
210
211
213 std::string(category) {
214}
215
216
217void
219 myOptions.push_back(std::make_pair(name, option));
220}
221
222
223const std::vector<std::pair<std::string, Option*> >&
225 return myOptions;
226}
227
228
229void
231 // just sort vector with options
232 std::sort(myOptions.begin(), myOptions.end());
233}
234
235
236void
237GNEPythonToolDialog::buildArguments(bool sortByName, bool groupedByCategories) {
238 // clear arguments and categories
239 for (const auto& argument : myArguments) {
240 delete argument;
241 }
242 for (const auto& category : myCategories) {
243 delete category;
244 }
245 myArguments.clear();
246 myCategories.clear();
247 // get argument sorted by name and grouped by categories
248 auto categoryOptions = groupedByCategories ? getOptionsByCategories(myPythonTool->getToolsOptions()) : getOptions(myPythonTool->getToolsOptions());
249 // calculate number of arguments
250 int numArguments = 0;
251 for (auto& categoryOption : categoryOptions) {
252 numArguments += (int)categoryOption.getOptions().size() + 1;
253 }
254 const int halfNumArguments = numArguments / 2;
255 // declare counter for number of inserted arguments
256 int numInsertedArguments = 0;
257 // iterate over category options
258 for (auto& categoryOption : categoryOptions) {
259 // get argument frame
260 auto argumentFrame = (numInsertedArguments < halfNumArguments) ? myArgumentFrameLeft : myArgumentFrameRight;
261 // add category
262 if (categoryOption.size() > 0) {
263 myCategories.push_back(new GNEPythonToolDialogElements::Category(argumentFrame, categoryOption));
264 numInsertedArguments++;
265 }
266 // check if sort by name
267 if (sortByName) {
268 categoryOption.sortByName();
269 }
270 // add options
271 for (const auto& option : categoryOption.getOptions()) {
272 // get argument frame (again)
273 argumentFrame = (numInsertedArguments < halfNumArguments) ? myArgumentFrameLeft : myArgumentFrameRight;
274 // continue depending of type
275 if (option.second->isInteger()) {
276 myArguments.push_back(new GNEPythonToolDialogElements::IntArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
277 } else if (option.second->isFloat()) {
278 myArguments.push_back(new GNEPythonToolDialogElements::FloatArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
279 } else if (option.second->isBool()) {
280 myArguments.push_back(new GNEPythonToolDialogElements::BoolArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
281 } else if (option.second->isFileName()) {
282 myArguments.push_back(new GNEPythonToolDialogElements::FileNameArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
283 } else if (option.second->isNetwork()) {
284 myArguments.push_back(new GNEPythonToolDialogElements::NetworkArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
285 } else if (option.second->isAdditional()) {
286 myArguments.push_back(new GNEPythonToolDialogElements::AdditionalArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
287 } else if (option.second->isRoute()) {
288 myArguments.push_back(new GNEPythonToolDialogElements::RouteArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
289 } else if (option.second->isData()) {
290 myArguments.push_back(new GNEPythonToolDialogElements::DataArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
291 } else if (option.second->isSumoConfig()) {
292 myArguments.push_back(new GNEPythonToolDialogElements::SumoConfigArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
293 } else if (option.second->isEdge()) {
294 myArguments.push_back(new GNEPythonToolDialogElements::EdgeArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
295 } else if (option.second->isEdgeVector()) {
296 myArguments.push_back(new GNEPythonToolDialogElements::EdgeVectorArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
297 } else {
298 myArguments.push_back(new GNEPythonToolDialogElements::StringArgument(this, myPythonTool, getApplicationWindow(), argumentFrame, option.first, option.second));
299 }
300 numInsertedArguments++;
301 }
302 }
303 // check if create arguments
304 if (id() > 0) {
305 for (auto& argument : myArguments) {
306 argument->create();
307 }
308 }
309 // adjust parameter column (call always after create elements)
311}
312
313
314void
316 int maximumWidth = 0;
317 // iterate over all arguments and find the maximum width
318 for (const auto& argument : myArguments) {
319 const auto label = argument->getParameterLabel();
320 const int columnWidth = label->getFont()->getTextWidth(label->getText().text(), label->getText().length() + MARGIN);
321 if (columnWidth > maximumWidth) {
322 maximumWidth = columnWidth;
323 }
324 }
325 // set maximum width for all parameter labels
326 for (const auto& argument : myArguments) {
327 argument->getParameterLabel()->setWidth(maximumWidth);
328 }
329}
330
331
332std::vector<GNEPythonToolDialog::CategoryOptions>
334 // use a vector with only one empty category to reuse code of buildArguments
335 std::vector<GNEPythonToolDialog::CategoryOptions> result = {GNEPythonToolDialog::CategoryOptions("")};
336 // add all options to result
337 for (const auto& option : optionsCont) {
338 result.front().addOption(option.first, option.second);
339 }
340 return result;
341}
342
343
344std::vector<GNEPythonToolDialog::CategoryOptions>
346 // declare vector with common categories
347 const std::vector<std::string> commonCategories = {"input", "output", "processing", "time"};
348 // fill categories
349 std::vector<std::string> categories = commonCategories;
350 for (const auto& option : optionsCont) {
351 if (std::find(categories.begin(), categories.end(), option.second->getSubTopic()) == categories.end()) {
352 categories.push_back(option.second->getSubTopic());
353 }
354 }
355 // declare vector of category options and fill
356 std::vector<GNEPythonToolDialog::CategoryOptions> result;
357 for (const auto& category : categories) {
358 result.push_back(GNEPythonToolDialog::CategoryOptions(category));
359 }
360 // fill result with options
361 for (const auto& option : optionsCont) {
362 auto category = std::find(result.begin(), result.end(), option.second->getSubTopic());
363 // add option in category
364 category->addOption(option.first, option.second);
365 }
366 // drop empty categories
367 auto it = result.begin();
368 while (it != result.end()) {
369 if (it->getOptions().empty()) {
370 it = result.erase(it);
371 } else {
372 it++;
373 }
374 }
375 return result;
376}
377
378
379int
381 const int column = (int)myArguments.size() / NUMROWSBYCOLUMN;
382 return (column < MAXNUMCOLUMNS) ? column : (MAXNUMCOLUMNS - 1);
383}
384
385
386FXVerticalFrame*
390
391
392FXVerticalFrame*
396
397/****************************************************************************/
DialogType
#define MARGIN
#define MAXNUMCOLUMNS
FXDEFMAP(GNEPythonToolDialog) GNEPythonToolDialogMap[]
#define NUMROWSBYCOLUMN
@ MID_GNE_SET_ATTRIBUTE
attribute edited
Definition GUIAppEnum.h:993
@ MID_GNE_BUTTON_RUN
run button
@ MID_CHOOSEN_SAVE
Save set.
Definition GUIAppEnum.h:605
@ MID_GNE_BUTTON_RESET
reset button
@ MID_GNE_RUNPYTHONTOOL
run python
Definition GUIAppEnum.h:759
@ MID_SHOWTOOLTIPS_MENU
Show tool tips in menus - button.
Definition GUIAppEnum.h:389
@ MID_CHOOSEN_LOAD
Load set.
Definition GUIAppEnum.h:603
#define GUIDesignScrollWindow
design for scroll windows extended over Y and y
Definition GUIDesigns.h:394
#define GUIDesignButtonConfiguration
Configuration Button.
Definition GUIDesigns.h:177
#define GUIDesignMFXCheckableButtonSquare
Definition GUIDesigns.h:158
#define GUIDesignCheckButton
checkButton placed in left position
Definition GUIDesigns.h:194
#define GUIDesignAuxiliarFrame
design for auxiliar (Without borders) frame extended in all directions
Definition GUIDesigns.h:409
#define GUIDesignHorizontalFrameNoPadding
Horizontal frame extended over frame parent without padding and spacing.
Definition GUIDesigns.h:350
GUIIcon
An enumeration of icons used by the gui applications.
Definition GUIIcons.h:33
@ SHOWTOOLTIPS_MENU
@ OPEN
open icons
@ SAVE
save icons
#define TL(string)
Definition MsgHandler.h:304
int GUIDesignHeight
the default height for GUI elements
Definition StdDefs.cpp:40
The main window of Netedit.
GNEViewNet * getViewNet()
get pointer to viewNet
GNEApplicationWindow * getApplicationWindow() const
get pointer to the application window
GNEApplicationWindow * myApplicationWindow
FOX needs this.
Definition GNEDialog.h:146
long closeDialogAccepting()
close dialog accepting the changes
OpenType
Open dialog type.
Definition GNEDialog.h:58
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
std::vector< CategoryOptions > getOptionsByCategories(OptionsCont &optionsCont) const
get options sorted by category
FXVerticalFrame * myArgumentFrameRight
argument frame right
GNEPythonTool * myPythonTool
python tool
void adjustParameterColumn()
adjust parameter column
int getNumRowColums() const
get number of row colums
long onCmdLoad(FXObject *, FXSelector, void *)
load options
std::vector< GNEPythonToolDialogElements::Argument * > myArguments
list of arguments sorted by categories
std::vector< GNEPythonToolDialogElements::Category * > myCategories
list of categories
long onCmdShowToolTipsMenu(FXObject *, FXSelector, void *)
enable/disable show toolTip
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 runInternalTest(const InternalTestStep::DialogArgument *dialogArgument)
run internal test
void buildArguments(bool sortByName, bool groupedByCategories)
build arguments
FXCheckButton * myGroupedCheckButton
check button to enable/diasble grouping
void saveConfiguration(const std::string &file) const
save configuration
bool loadConfiguration(const std::string &file)
load configuration
FXMenuCommand * getMenuCommand() const
get menu command
OptionsCont & getToolsOptions()
get tools options
GNEViewParent * getViewParent() const
get the net object
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
dialog arguments, used for certain modal dialogs that can not be edited using tab
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:74
A storage for options typed value containers)
Definition OptionsCont.h:89
static StringBijection< XMLFileExtension > XMLFileExtensions
XML file Extensions.
Definition json.hpp:4471