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
125 myShowToolTipsMenu->setChecked(!myShowToolTipsMenu->amChecked());
126 if (myApplicationWindow->getViewNet()) {
127 myApplicationWindow->getViewNet()->getViewParent()->getShowToolTipsMenu()->setChecked(myShowToolTipsMenu->amChecked());
128 myApplicationWindow->getViewNet()->getViewParent()->getShowToolTipsMenu()->update();
129 }
130 // enable/disable static tooltip
131 myApplicationWindow->getStaticTooltipMenu()->enableStaticToolTip(myShowToolTipsMenu->amChecked());
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*> >&
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
Definition GUIIcons.h:190
@ OPEN
open icons
Definition GUIIcons.h:77
@ TOOL_PYTHON
Definition GUIIcons.h:161
@ SAVE
save icons
Definition GUIIcons.h:90
#define TL(string)
Definition MsgHandler.h:304
int GUIDesignHeight
the default height for GUI elements
Definition StdDefs.cpp:40
The main window of Netedit.
FXVerticalFrame * myContentFrame
content frame
Definition GNEDialog.h:152
GNEApplicationWindow * getApplicationWindow() const
get pointer to the application window
GNEApplicationWindow * myApplicationWindow
FOX needs this.
Definition GNEDialog.h:146
void openDialog(FXWindow *focusableElement=nullptr)
open dialog
long closeDialogAccepting()
close dialog accepting the changes
OpenType
Open dialog type.
Definition GNEDialog.h:58
GNEDialog(GNEApplicationWindow *applicationWindow, const std::string &name, GUIIcon titleIcon, DialogType type, Buttons buttons, OpenType openType, ResizeMode resizeMode)
basic constructor
Definition GNEDialog.cpp:60
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< std::pair< std::string, Option * > > myOptions
options for this category
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
GNEPythonToolDialog(GNEApplicationWindow *applicationWindow, GNEPythonTool *tool)
Constructor.
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
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
dialog arguments, used for certain modal dialogs that can not be edited using tab
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