Line data Source code
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 : /****************************************************************************/
14 : /// @file MFXDecalsTable.cpp
15 : /// @author Pablo Alvarez Lopez
16 : /// @date Feb 2023
17 : ///
18 : // Table used for show and edit decal values
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/gui/div/GUIDesigns.h>
23 : #include <utils/gui/images/GUIIconSubSys.h>
24 : #include <utils/gui/windows/GUIAppEnum.h>
25 : #include <utils/gui/windows/GUIDialog_ViewSettings.h>
26 : #include <utils/gui/windows/GUIGlChildWindow.h>
27 : #include <utils/gui/windows/GUIMainWindow.h>
28 :
29 : #include "MFXDecalsTable.h"
30 :
31 :
32 : #define EXTRAMARGIN 4
33 :
34 : #define MAXROWS 100
35 :
36 : // ===========================================================================
37 : // FOX callback mapping
38 : // ===========================================================================
39 :
40 : FXDEFMAP(MFXDecalsTable) MFXDecalsTableMap[] = {
41 : FXMAPFUNC(MID_MBTTIP_FOCUS, 0, MFXDecalsTable::onFocusRow),
42 : FXMAPFUNC(SEL_FOCUSIN, MID_DECALSTABLE_TEXTFIELD, MFXDecalsTable::onFocusRow),
43 : FXMAPFUNC(SEL_KEYPRESS, MID_DECALSTABLE_TEXTFIELD, MFXDecalsTable::onCmdKeyPress),
44 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_TEXTFIELD, MFXDecalsTable::onCmdEditRowString),
45 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_SPINNER, MFXDecalsTable::onCmdEditRowSpinner),
46 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_CHECKBOX, MFXDecalsTable::onCmdEditRowCheckBox),
47 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_OPEN, MFXDecalsTable::onCmdOpenDecal),
48 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_ADD, MFXDecalsTable::onCmdAddRow),
49 : FXMAPFUNC(SEL_UPDATE, MID_DECALSTABLE_ADD, MFXDecalsTable::onUpdAddRow),
50 : FXMAPFUNC(SEL_COMMAND, MID_DECALSTABLE_REMOVE, MFXDecalsTable::onCmdRemoveRow),
51 : };
52 :
53 : // Object implementation
54 0 : FXIMPLEMENT(MFXDecalsTable, FXVerticalFrame, MFXDecalsTableMap, ARRAYNUMBER(MFXDecalsTableMap))
55 :
56 : // ===========================================================================
57 : // method definitions
58 : // ===========================================================================
59 :
60 : // ---------------------------------------------------------------------------
61 : // MFXDecalsTable - public methods
62 : // ---------------------------------------------------------------------------
63 :
64 0 : MFXDecalsTable::MFXDecalsTable(GUIDialog_ViewSettings* dialogViewSettingsParent, FXComposite* parent) :
65 : FXVerticalFrame(parent, GUIDesignAuxiliarFrameFixHeight),
66 0 : myIndexFont(new FXFont(getApp(), "Segoe UI", 9)),
67 0 : myIndexSelectedFont(new FXFont(getApp(), "Segoe UI", 9, FXFont::Bold)),
68 0 : myDialogViewSettings(dialogViewSettingsParent) {
69 : // create vertical frame for rows
70 0 : myColumnsFrame = new FXHorizontalFrame(this, GUIDesignAuxiliarFrame);
71 : // create add button
72 0 : myAddButton = GUIDesigns::buildFXButton(this, "", TL("Add decal"), TL("Add decal."),
73 : GUIIconSubSys::getIcon(GUIIcon::ADD), this, MID_DECALSTABLE_ADD, GUIDesignButtonIcon);
74 0 : }
75 :
76 :
77 0 : MFXDecalsTable::~MFXDecalsTable() {
78 : // delete fonts
79 0 : delete myIndexFont;
80 0 : delete myIndexSelectedFont;
81 0 : }
82 :
83 :
84 : void
85 0 : MFXDecalsTable::clearTable() {
86 : // clear rows (always before columns, because delete row delete also all cells)
87 0 : for (const auto& row : myRows) {
88 0 : delete row;
89 : }
90 : // clear columns
91 0 : for (const auto& column : myColumns) {
92 0 : delete column;
93 : }
94 : // drop rows and columns
95 : myRows.clear();
96 : myColumns.clear();
97 0 : }
98 :
99 :
100 : void
101 0 : MFXDecalsTable::fillTable() {
102 : // first clear table
103 0 : clearTable();
104 : // get decals
105 0 : const auto decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
106 : // create columns
107 0 : std::string columnsType = "ibfppppppcd";
108 0 : for (int i = 0; i < (FXint)columnsType.size(); i++) {
109 0 : myColumns.push_back(new Column(this, i, columnsType.at(i)));
110 : }
111 : // get num decals
112 0 : const int numDecals = decals.size() < MAXROWS ? (int)decals.size() : MAXROWS;
113 : // create rows
114 0 : for (int i = 0; i < numDecals; i++) {
115 : // get decal
116 0 : const auto& decal = decals.at(i);
117 : // create row
118 0 : auto row = new Row(this);
119 : // fill cells
120 0 : row->getCells().at(2)->getTextField()->setText(decal.filename.c_str());
121 0 : row->getCells().at(3)->getSpinner()->setValue(decal.centerX);
122 0 : row->getCells().at(4)->getSpinner()->setValue(decal.centerY);
123 0 : row->getCells().at(5)->getSpinner()->setValue(decal.width);
124 0 : row->getCells().at(6)->getSpinner()->setValue(decal.height);
125 0 : row->getCells().at(7)->getSpinner()->setValue(decal.rot);
126 0 : row->getCells().at(8)->getSpinner()->setValue(decal.layer);
127 0 : if (decal.screenRelative) {
128 0 : row->getCells().at(9)->getCheckButton()->setCheck(true);
129 0 : row->getCells().at(9)->getCheckButton()->setText("true");
130 : } else {
131 0 : row->getCells().at(9)->getCheckButton()->setCheck(false);
132 0 : row->getCells().at(9)->getCheckButton()->setText("false");
133 : }
134 0 : myRows.push_back(row);
135 : }
136 : // set headers
137 0 : myColumns.at(2)->setColumnLabel("filename", "");
138 0 : myColumns.at(3)->setColumnLabel("centerX", "");
139 0 : myColumns.at(4)->setColumnLabel("centerY", "");
140 0 : myColumns.at(5)->setColumnLabel("width", "");
141 0 : myColumns.at(6)->setColumnLabel("height", "");
142 0 : myColumns.at(7)->setColumnLabel("rotation", "");
143 0 : myColumns.at(8)->setColumnLabel("layer", "");
144 0 : myColumns.at(9)->setColumnLabel("sRel", "screen relative");
145 : // adjust height (header + rows + add button)
146 0 : setHeight((numDecals + 2) * GUIDesignHeight);
147 : // call create to create all row's elements
148 0 : create();
149 0 : }
150 :
151 :
152 : void
153 0 : MFXDecalsTable::setItemText(FXint row, FXint column, const std::string& text) {
154 0 : if ((row >= 0) && (row < (FXint)myRows.size()) &&
155 0 : (column >= 0) && (column < (FXint)myColumns.size())) {
156 0 : myRows.at(row)->setText(column, text);
157 : } else {
158 0 : throw ProcessError(TL("Invalid row or column"));
159 : }
160 0 : }
161 :
162 :
163 : std::string
164 0 : MFXDecalsTable::getItemText(const int row, const int column) const {
165 0 : if ((row >= 0) && (row < (FXint)myRows.size()) &&
166 0 : (column >= 0) && (column < (FXint)myColumns.size())) {
167 0 : return myRows.at(row)->getText(column);
168 : }
169 0 : throw ProcessError(TL("Invalid row or column"));
170 : }
171 :
172 :
173 : int
174 0 : MFXDecalsTable::getNumRows() const {
175 0 : return (int)myRows.size();
176 : }
177 :
178 :
179 : int
180 0 : MFXDecalsTable::getCurrentSelectedRow() const {
181 0 : return myCurrentSelectedRow;
182 : }
183 :
184 :
185 : void
186 0 : MFXDecalsTable::selectRow(const int row) {
187 0 : if ((row >= 0) && (row < (FXint)myRows.size())) {
188 : // update current selected row
189 0 : myCurrentSelectedRow = row;
190 : // update index label
191 0 : updateIndexLabel();
192 : } else {
193 0 : throw ProcessError(TL("Invalid row"));
194 : }
195 0 : }
196 :
197 :
198 : void
199 0 : MFXDecalsTable::setColumnLabel(const int column, const std::string& text, const std::string& tooltip) {
200 0 : if ((column >= 0) && (column < (int)myColumns.size())) {
201 0 : myColumns.at(column)->setColumnLabel(text, tooltip);
202 : } else {
203 0 : throw ProcessError(TL("Invalid column"));
204 : }
205 0 : }
206 :
207 :
208 : long
209 0 : MFXDecalsTable::onFocusRow(FXObject* sender, FXSelector, void*) {
210 : int selectedRow = -1;
211 : // search selected text field
212 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
213 : // iterate over every cell
214 0 : for (const auto& cell : myRows.at(rowIndex)->getCells()) {
215 0 : if ((cell->getTextField() == sender) || (cell->getButton() == sender)) {
216 : selectedRow = rowIndex;
217 : }
218 : }
219 : }
220 : // update index label
221 0 : updateIndexLabel();
222 : // set new row
223 0 : if (myCurrentSelectedRow != selectedRow) {
224 0 : myCurrentSelectedRow = selectedRow;
225 0 : updateIndexLabel();
226 : }
227 0 : return 0;
228 : }
229 :
230 :
231 : long
232 0 : MFXDecalsTable::onCmdKeyPress(FXObject* sender, FXSelector sel, void* ptr) {
233 : // get FXEvent
234 : FXEvent* eventInfo = (FXEvent*)ptr;
235 : // check code
236 0 : if (eventInfo->code == 65362) {
237 : // move up
238 0 : if (myCurrentSelectedRow > 0) {
239 0 : myCurrentSelectedRow -= 1;
240 : } else {
241 : // we're in the first, then select last
242 0 : myCurrentSelectedRow = ((int)myRows.size() - 1);
243 : }
244 : // update index label
245 0 : updateIndexLabel();
246 : // move focus
247 0 : moveFocus();
248 0 : return 1;
249 0 : } else if (eventInfo->code == 65364) {
250 : // move down
251 0 : if (myCurrentSelectedRow < ((int)myRows.size() - 1)) {
252 0 : myCurrentSelectedRow += 1;
253 : } else {
254 : // we're in the last, then select first
255 0 : myCurrentSelectedRow = 0;
256 : }
257 : // update index label
258 0 : updateIndexLabel();
259 : // move focus
260 0 : moveFocus();
261 0 : return 1;
262 : } else {
263 : // continue handling key pres
264 0 : return sender->handle(sender, sel, ptr);
265 : }
266 : }
267 :
268 :
269 : long
270 0 : MFXDecalsTable::onCmdEditRowString(FXObject* sender, FXSelector, void*) {
271 : // get decals
272 0 : auto& decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
273 : // get value
274 0 : const std::string value = dynamic_cast<FXTextField*>(sender)->getText().text();
275 : // set filename
276 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
277 : // continue depending of string
278 0 : if (myRows.at(rowIndex)->getCells().at(2)->getTextField() == sender) {
279 0 : decals.at(rowIndex).filename = value;
280 : }
281 : }
282 : // update view
283 0 : myDialogViewSettings->getSUMOAbstractView()->update();
284 0 : return 1;
285 : }
286 :
287 :
288 : long
289 0 : MFXDecalsTable::onCmdEditRowSpinner(FXObject* sender, FXSelector, void*) {
290 : // get decals
291 0 : auto& decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
292 : // get value
293 0 : const auto value = dynamic_cast<FXRealSpinner*>(sender)->getValue();
294 : // set filename
295 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
296 0 : if (myRows.at(rowIndex)->getCells().at(3)->getSpinner() == sender) {
297 0 : decals.at(rowIndex).centerX = value;
298 0 : } else if (myRows.at(rowIndex)->getCells().at(4)->getSpinner() == sender) {
299 0 : decals.at(rowIndex).centerY = value;
300 0 : } else if (myRows.at(rowIndex)->getCells().at(5)->getSpinner() == sender) {
301 0 : decals.at(rowIndex).width = value;
302 0 : } else if (myRows.at(rowIndex)->getCells().at(6)->getSpinner() == sender) {
303 0 : decals.at(rowIndex).height = value;
304 0 : } else if (myRows.at(rowIndex)->getCells().at(7)->getSpinner() == sender) {
305 0 : decals.at(rowIndex).rot = value;
306 0 : } else if (myRows.at(rowIndex)->getCells().at(8)->getSpinner() == sender) {
307 0 : decals.at(rowIndex).layer = value;
308 : }
309 : }
310 : // update view
311 0 : myDialogViewSettings->getSUMOAbstractView()->update();
312 0 : return 1;
313 : }
314 :
315 :
316 : long
317 0 : MFXDecalsTable::onCmdEditRowCheckBox(FXObject* sender, FXSelector, void*) {
318 : // get decals
319 0 : auto& decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
320 : // get check buton
321 0 : auto checkButton = dynamic_cast<FXCheckButton*>(sender);
322 : // update text
323 0 : checkButton->setText((checkButton->getCheck() == TRUE) ? "true" : "false");
324 : // set filename
325 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
326 0 : if (myRows.at(rowIndex)->getCells().at(9)->getCheckButton() == sender) {
327 0 : decals.at(rowIndex).screenRelative = (checkButton->getCheck() == TRUE) ? true : false;
328 : }
329 : }
330 : // update view
331 0 : myDialogViewSettings->getSUMOAbstractView()->update();
332 0 : return 1;
333 : }
334 :
335 :
336 : long
337 0 : MFXDecalsTable::onCmdOpenDecal(FXObject* sender, FXSelector, void*) {
338 : // configure open dialog
339 0 : FXFileDialog opendialog(this, TL("Open decal"));
340 : // select existing file
341 0 : opendialog.setSelectMode(SELECTFILE_EXISTING);
342 : // set icon and pattern list
343 0 : opendialog.setIcon(GUIIconSubSys::getIcon(GUIIcon::OPEN));
344 0 : opendialog.setPatternList(SUMOXMLDefinitions::ImageFileExtensions.getMultilineString().c_str());
345 : // set current folder
346 0 : if (gCurrentFolder.length() != 0) {
347 0 : opendialog.setDirectory(gCurrentFolder);
348 : }
349 : // open dialog
350 0 : opendialog.execute();
351 : // check if file exist
352 0 : if (!opendialog.getFilename().empty()) {
353 : // get decals
354 0 : auto& decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
355 : // set filename
356 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
357 0 : if (myRows.at(rowIndex)->getCells().at(1)->getButton() == sender) {
358 : // set text in filename
359 0 : myRows.at(rowIndex)->getCells().at(2)->getTextField()->setText(opendialog.getFilename());
360 : // update filename in decal
361 0 : decals.at(rowIndex).filename = opendialog.getFilename().text();
362 : // update view
363 0 : myDialogViewSettings->getSUMOAbstractView()->update();
364 : return 1;
365 : }
366 : }
367 : }
368 : return 1;
369 0 : }
370 :
371 :
372 : long
373 0 : MFXDecalsTable::onCmdAddRow(FXObject*, FXSelector, void*) {
374 : // add a new decal
375 0 : myDialogViewSettings->getSUMOAbstractView()->getDecals().push_back(GUISUMOAbstractView::Decal());
376 : // refill table
377 0 : fillTable();
378 0 : return 1;
379 : }
380 :
381 :
382 : long
383 0 : MFXDecalsTable::onUpdAddRow(FXObject* sender, FXSelector, void* ptr) {
384 0 : if (myDialogViewSettings->getSUMOAbstractView()->getDecals().size() < MAXROWS) {
385 0 : return sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
386 : } else {
387 0 : return sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
388 : }
389 : }
390 :
391 :
392 : long
393 0 : MFXDecalsTable::onCmdRemoveRow(FXObject* sender, FXSelector, void*) {
394 : // get decals
395 0 : auto& decals = myDialogViewSettings->getSUMOAbstractView()->getDecals();
396 : // search row
397 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
398 0 : if (myRows.at(rowIndex)->getCells().back()->getButton() == sender) {
399 : // remove row
400 : decals.erase(decals.begin() + rowIndex);
401 : // update view
402 0 : myDialogViewSettings->getSUMOAbstractView()->update();
403 : // refill table
404 0 : fillTable();
405 0 : return 1;
406 : }
407 : }
408 : return 1;
409 : }
410 :
411 :
412 : void
413 0 : MFXDecalsTable::updateIndexLabel() {
414 : // update radio buttons checks
415 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
416 : // iterate over every cell
417 0 : for (const auto& cell : myRows.at(rowIndex)->getCells()) {
418 0 : if (cell->getIndexLabel()) {
419 0 : if (myCurrentSelectedRow == rowIndex) {
420 0 : cell->showIndexLabelBold();
421 : } else {
422 0 : cell->showIndexLabelNormal();
423 : }
424 : }
425 : }
426 : }
427 0 : }
428 :
429 :
430 : bool
431 0 : MFXDecalsTable::moveFocus() {
432 : // first find focus
433 : // update radio buttons checks
434 0 : for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
435 0 : for (int cellIndex = 0; cellIndex < (int)myRows.at(rowIndex)->getCells().size(); cellIndex++) {
436 0 : if (myRows.at(rowIndex)->getCells().at(cellIndex)->hasFocus()) {
437 : // set focus in current row
438 0 : myRows.at(myCurrentSelectedRow)->getCells().at(cellIndex)->setFocus();
439 0 : return true;
440 : }
441 : }
442 : }
443 : return false;
444 : }
445 :
446 : // ---------------------------------------------------------------------------
447 : // MFXDecalsTable::Cell - methods
448 : // ---------------------------------------------------------------------------
449 :
450 0 : MFXDecalsTable::Cell::Cell(MFXDecalsTable* decalsTable, FXTextField* textField, int col, int row) :
451 0 : myDecalsTable(decalsTable),
452 0 : myTextField(textField),
453 0 : myCol(col),
454 0 : myRow(row) {
455 0 : }
456 :
457 :
458 0 : MFXDecalsTable::Cell::Cell(MFXDecalsTable* decalsTable, FXLabel* indexLabel, FXLabel* indexLabelBold, int col, int row) :
459 0 : myDecalsTable(decalsTable),
460 0 : myIndexLabel(indexLabel),
461 0 : myIndexLabelBold(indexLabelBold),
462 0 : myCol(col),
463 0 : myRow(row) {
464 : // hide bold and set background
465 0 : indexLabelBold->hide();
466 0 : indexLabelBold->setBackColor(FXRGBA(210, 233, 255, 255));
467 0 : }
468 :
469 :
470 0 : MFXDecalsTable::Cell::Cell(MFXDecalsTable* decalsTable, FXButton* button, int col, int row) :
471 0 : myDecalsTable(decalsTable),
472 0 : myButton(button),
473 0 : myCol(col),
474 0 : myRow(row) {
475 0 : }
476 :
477 :
478 0 : MFXDecalsTable::Cell::Cell(MFXDecalsTable* decalsTable, FXCheckButton* checkButton, int col, int row) :
479 0 : myDecalsTable(decalsTable),
480 0 : myCheckButton(checkButton),
481 0 : myCol(col),
482 0 : myRow(row) {
483 0 : }
484 :
485 :
486 0 : MFXDecalsTable::Cell::Cell(MFXDecalsTable* decalsTable, FXRealSpinner* spinner, int col, int row) :
487 0 : myDecalsTable(decalsTable),
488 0 : mySpinner(spinner),
489 0 : myCol(col),
490 0 : myRow(row) {
491 0 : }
492 :
493 :
494 0 : MFXDecalsTable::Cell::~Cell() {
495 : // delete all elements
496 0 : if (myTextField) {
497 0 : delete myTextField;
498 : }
499 0 : if (myIndexLabel) {
500 0 : delete myIndexLabel;
501 : }
502 0 : if (myIndexLabelBold) {
503 0 : delete myIndexLabelBold;
504 : }
505 0 : if (myButton) {
506 0 : delete myButton;
507 : }
508 0 : if (myCheckButton) {
509 0 : delete myCheckButton;
510 : }
511 0 : }
512 :
513 :
514 : bool
515 0 : MFXDecalsTable::Cell::hasFocus() const {
516 : // check if one of the cell elements has the focus
517 0 : if (myTextField && myTextField->hasFocus()) {
518 : return true;
519 0 : } else if (myButton && myButton->hasFocus()) {
520 : return true;
521 0 : } else if (myCheckButton && myCheckButton->hasFocus()) {
522 : return true;
523 : } else {
524 0 : return false;
525 : }
526 : }
527 :
528 :
529 : void
530 0 : MFXDecalsTable::Cell::setFocus() {
531 : // set focus
532 0 : if (myTextField) {
533 0 : myTextField->setFocus();
534 0 : } else if (myButton) {
535 0 : myButton->setFocus();
536 0 : } else if (myCheckButton) {
537 0 : myCheckButton->setFocus();
538 : }
539 0 : }
540 :
541 :
542 : FXTextField*
543 0 : MFXDecalsTable::Cell::getTextField() const {
544 0 : return myTextField;
545 : }
546 :
547 :
548 : FXLabel*
549 0 : MFXDecalsTable::Cell::getIndexLabel() const {
550 0 : return myIndexLabel;
551 : }
552 :
553 :
554 : FXButton*
555 0 : MFXDecalsTable::Cell::getButton() {
556 0 : return myButton;
557 : }
558 :
559 :
560 : FXCheckButton*
561 0 : MFXDecalsTable::Cell::getCheckButton() {
562 0 : return myCheckButton;
563 : }
564 :
565 :
566 : FXRealSpinner*
567 0 : MFXDecalsTable::Cell::getSpinner() {
568 0 : return mySpinner;
569 : }
570 :
571 :
572 : void
573 0 : MFXDecalsTable::Cell::showIndexLabelNormal() {
574 0 : myIndexLabel->show();
575 0 : myIndexLabelBold->hide();
576 : // recalc both
577 0 : myIndexLabel->recalc();
578 0 : myIndexLabelBold->recalc();
579 0 : }
580 :
581 :
582 : void
583 0 : MFXDecalsTable::Cell::showIndexLabelBold() {
584 0 : myIndexLabel->hide();
585 0 : myIndexLabelBold->show();
586 : // recalc both
587 0 : myIndexLabel->recalc();
588 0 : myIndexLabelBold->recalc();
589 0 : }
590 :
591 :
592 : int
593 0 : MFXDecalsTable::Cell::getCol() const {
594 0 : return myCol;
595 : }
596 :
597 :
598 : int
599 0 : MFXDecalsTable::Cell::getRow() const {
600 0 : return myRow;
601 : }
602 :
603 :
604 : char
605 0 : MFXDecalsTable::Cell::getType() const {
606 0 : return myDecalsTable->myColumns.at(myCol)->getType();
607 : }
608 :
609 :
610 0 : MFXDecalsTable::Cell::Cell() :
611 0 : myCol(-1),
612 0 : myRow(-1) {
613 0 : }
614 :
615 : // ---------------------------------------------------------------------------
616 : // MFXDecalsTable::Column - methods
617 : // ---------------------------------------------------------------------------
618 :
619 0 : MFXDecalsTable::Column::Column(MFXDecalsTable* table, const int index, const char type) :
620 0 : myTable(table),
621 0 : myIndex(index),
622 0 : myType(type) {
623 : // get static tooltip
624 0 : auto staticTooltip = table->myDialogViewSettings->getSUMOAbstractView()->getGUIGlChildWindow()->getGUIMainWindowParent()->getStaticTooltipMenu();
625 : // create vertical frame
626 0 : if (myType == 'f') {
627 0 : myVerticalFrame = new FXVerticalFrame(table->myColumnsFrame, GUIDesignAuxiliarFrame);
628 : } else {
629 0 : myVerticalFrame = new FXVerticalFrame(table->myColumnsFrame, GUIDesignAuxiliarFrameFixedWidth(100));
630 : }
631 : // create top label
632 0 : switch (myType) {
633 0 : case ('f'): {
634 : // ticked label extended
635 0 : myTopLabel = new MFXLabelTooltip(myVerticalFrame, staticTooltip, "", nullptr, GUIDesignLabelThick(JUSTIFY_NORMAL));
636 0 : break;
637 : }
638 0 : case ('p'):
639 : case ('s'): {
640 : // ticked label fixed
641 0 : myTopLabel = new MFXLabelTooltip(myVerticalFrame, staticTooltip, "", nullptr, GUIDesignLabelThickedFixed(0));
642 0 : break;
643 : }
644 0 : case ('c'): {
645 : // ticked label for checkbox
646 0 : myTopLabel = new MFXLabelTooltip(myVerticalFrame, staticTooltip, "", nullptr, GUIDesignLabelThickedFixed(30));
647 0 : break;
648 : }
649 0 : case ('i'): {
650 : // ticked label for index
651 0 : myTopLabel = new MFXLabelTooltip(myVerticalFrame, staticTooltip, "", nullptr, GUIDesignLabelFixed(30));
652 0 : break;
653 : }
654 0 : default: {
655 : // empty label (for buttons)
656 0 : myTopLabel = new MFXLabelTooltip(myVerticalFrame, staticTooltip, "", nullptr, GUIDesignLabelFixed(0));
657 0 : break;
658 : }
659 : }
660 : // create vertical frame for cells
661 0 : if (myType == 'f') {
662 0 : myVerticalCellFrame = new FXVerticalFrame(myVerticalFrame, GUIDesignAuxiliarFrame);
663 : } else {
664 0 : myVerticalCellFrame = new FXVerticalFrame(myVerticalFrame, GUIDesignAuxiliarFrameFixedWidth(100));
665 : }
666 : // create elements
667 0 : myVerticalFrame->create();
668 0 : myTopLabel->create();
669 0 : myVerticalCellFrame->create();
670 : // adjust column width
671 0 : adjustColumnWidth();
672 0 : }
673 :
674 :
675 0 : MFXDecalsTable::Column::~Column() {
676 : // delete vertical frame (this also delete all childrens)
677 0 : delete myVerticalFrame;
678 0 : }
679 :
680 :
681 : FXVerticalFrame*
682 0 : MFXDecalsTable::Column::getVerticalCellFrame() const {
683 0 : return myVerticalCellFrame;
684 : }
685 :
686 :
687 : char
688 0 : MFXDecalsTable::Column::getType() const {
689 0 : return myType;
690 : }
691 :
692 :
693 : FXString
694 0 : MFXDecalsTable::Column::getColumnLabel() const {
695 0 : return myTopLabel->getText();
696 : }
697 :
698 :
699 : void
700 0 : MFXDecalsTable::Column::setColumnLabel(const std::string& text, const std::string& tooltip) {
701 0 : myTopLabel->setText(text.c_str());
702 0 : myTopLabel->setTipText(tooltip.c_str());
703 : // adjust column width
704 0 : adjustColumnWidth();
705 0 : }
706 :
707 :
708 : void
709 0 : MFXDecalsTable::Column::adjustColumnWidth() {
710 : // filename always extended
711 0 : if (myType != 'f') {
712 : // declare columnWidth
713 0 : int columnWidth = GUIDesignHeight;
714 : // adjust depending of label
715 0 : if ((myType == 's') || (myType == 'p') || (myType == 'c')) {
716 : // calculate top label width
717 0 : columnWidth = myTopLabel->getFont()->getTextWidth(myTopLabel->getText().text(), myTopLabel->getText().length() + EXTRAMARGIN);
718 : }
719 : // adjust width in all rows
720 0 : for (const auto& row : myTable->myRows) {
721 0 : if (row->getCells().at(myIndex)->getTextField()) {
722 0 : row->getCells().at(myIndex)->getTextField()->setWidth(columnWidth);
723 0 : } else if (row->getCells().at(myIndex)->getButton()) {
724 0 : row->getCells().at(myIndex)->getButton()->setWidth(columnWidth);
725 0 : } else if (row->getCells().at(myIndex)->getSpinner()) {
726 0 : row->getCells().at(myIndex)->getSpinner()->setWidth(columnWidth);
727 : }
728 : }
729 : // adjust labels and vertical frames
730 0 : myVerticalFrame->setWidth(columnWidth);
731 0 : myTopLabel->setWidth(columnWidth);
732 0 : myVerticalCellFrame->setWidth(columnWidth);
733 : }
734 0 : }
735 :
736 :
737 0 : MFXDecalsTable::Column::Column() :
738 0 : myIndex(0),
739 0 : myType('-') {}
740 :
741 : // ---------------------------------------------------------------------------
742 : // MFXDecalsTable::Row - methods
743 : // ---------------------------------------------------------------------------
744 :
745 0 : MFXDecalsTable::Row::Row(MFXDecalsTable* table) :
746 0 : myTable(table) {
747 : // build textFields
748 0 : for (int columnIndex = 0; columnIndex < (FXint)table->myColumns.size(); columnIndex++) {
749 : // get number of cells
750 0 : const int numCells = (int)myCells.size();
751 : // continue depending of type
752 0 : switch (table->myColumns.at(columnIndex)->getType()) {
753 0 : case ('f'): {
754 : // create textField for filenames
755 0 : auto textField = new FXTextField(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
756 0 : GUIDesignTextFieldNCol, table, MID_DECALSTABLE_TEXTFIELD, GUIDesignTextField);
757 0 : myCells.push_back(new Cell(table, textField, columnIndex, numCells));
758 0 : break;
759 : }
760 0 : case ('s'): {
761 : // create textField for textfiedl real values
762 0 : auto textField = new FXTextField(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
763 0 : GUIDesignTextFieldNCol, table, MID_DECALSTABLE_TEXTFIELD, GUIDesignTextFieldFixedRestricted(0, TEXTFIELD_REAL));
764 0 : myCells.push_back(new Cell(table, textField, columnIndex, numCells));
765 0 : break;
766 : }
767 0 : case ('p'): {
768 : // create spinner for real values
769 0 : auto spinner = new FXRealSpinner(table->myColumns.at(columnIndex)->getVerticalCellFrame(), GUIDesignTextFieldNCol,
770 0 : table, MID_DECALSTABLE_SPINNER, GUIDesignSpinDialDecalsTable);
771 0 : myCells.push_back(new Cell(table, spinner, columnIndex, numCells));
772 0 : break;
773 : }
774 0 : case ('i'): {
775 : // create labels for index
776 0 : auto indexLabel = new FXLabel(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
777 0 : toString(myTable->myRows.size()).c_str(), nullptr, GUIDesignLabelThickedFixed(30));
778 0 : auto indexLabelBold = new FXLabel(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
779 0 : toString(myTable->myRows.size()).c_str(), nullptr, GUIDesignLabelThickedFixed(30));
780 : // set fonts
781 0 : indexLabel->setFont(myTable->myIndexFont);
782 0 : indexLabelBold->setFont(myTable->myIndexSelectedFont);
783 0 : myCells.push_back(new Cell(table, indexLabel, indexLabelBold, columnIndex, numCells));
784 0 : break;
785 : }
786 0 : case ('c'): {
787 : // create checkbox for
788 0 : auto checkableButton = new FXCheckButton(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
789 0 : "false", table, MID_DECALSTABLE_CHECKBOX, GUIDesignMFXCheckableButton);
790 0 : myCells.push_back(new Cell(table, checkableButton, columnIndex, numCells));
791 0 : break;
792 : }
793 0 : case ('b'): {
794 : // create button for open decal
795 0 : auto button = GUIDesigns::buildFXButton(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
796 0 : "", TL("Open decal"), TL("Open decal."),
797 : GUIIconSubSys::getIcon(GUIIcon::OPEN), table, MID_DECALSTABLE_OPEN, GUIDesignButtonIcon);
798 0 : myCells.push_back(new Cell(table, button, columnIndex, numCells));
799 0 : break;
800 : }
801 0 : case ('d'): {
802 : // create button for delete decal
803 0 : auto button = GUIDesigns::buildFXButton(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
804 0 : "", TL("Remove decal"), TL("Remove decal."),
805 : GUIIconSubSys::getIcon(GUIIcon::REMOVE), table, MID_DECALSTABLE_REMOVE, GUIDesignButtonIcon);
806 0 : myCells.push_back(new Cell(table, button, columnIndex, numCells));
807 0 : break;
808 : }
809 0 : default:
810 0 : throw ProcessError("Invalid Cell type");
811 : }
812 : }
813 0 : }
814 :
815 :
816 0 : MFXDecalsTable::Row::~Row() {
817 : // delete all cells
818 0 : for (const auto& cell : myCells) {
819 0 : delete cell;
820 : }
821 0 : }
822 :
823 :
824 : std::string
825 0 : MFXDecalsTable::Row::getText(int index) const {
826 0 : if (myCells.at(index)->getTextField()) {
827 0 : return myCells.at(index)->getTextField()->getText().text();
828 : } else {
829 0 : throw ProcessError("Cell doesn't have a textField");
830 : }
831 : }
832 :
833 :
834 : void
835 0 : MFXDecalsTable::Row::setText(int index, const std::string& text) const {
836 : // set text
837 0 : myCells.at(index)->getTextField()->setText(text.c_str());
838 0 : }
839 :
840 :
841 : const std::vector<MFXDecalsTable::Cell*>&
842 0 : MFXDecalsTable::Row::getCells() const {
843 0 : return myCells;
844 : }
845 :
846 :
847 0 : MFXDecalsTable::Row::Row() {}
848 :
849 : /****************************************************************************/
|