Eclipse SUMO - Simulation of Urban MObility
MFXAddEditTypedTable.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2004-2022 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 // missing_desc
19 /****************************************************************************/
20 #include <config.h>
21 
23 #include <utils/common/ToString.h>
24 #include "MFXAddEditTypedTable.h"
25 
26 
27 // Map
28 FXDEFMAP(MFXAddEditTypedTable) MFXAddEditTypedTableMap[] = {
29  FXMAPFUNC(SEL_CLICKED, 0, MFXAddEditTypedTable::onClicked),
30  FXMAPFUNC(SEL_DOUBLECLICKED, 0, MFXAddEditTypedTable::onDoubleClicked),
31  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, MFXAddEditTypedTable::onLeftBtnRelease),
32  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, MFXAddEditTypedTable::onLeftBtnPress),
33 };
34 // Object implementation
35 FXIMPLEMENT(MFXAddEditTypedTable, FXTable, MFXAddEditTypedTableMap, ARRAYNUMBER(MFXAddEditTypedTableMap))
36 
37 
38 MFXAddEditTypedTable::MFXAddEditTypedTable(FXComposite* p, FXObject* tgt,
39  FXSelector sel, FXuint opts,
40  FXint x, FXint y, FXint w, FXint h,
41  FXint pl, FXint pr, FXint pt, FXint pb)
42  : FXTable(p, tgt, sel, opts, x, y, w, h, pl, pr, pt, pb) {}
43 
44 
46 
47 /*
48 void
49 MFXAddEditTypedTable::editItem(FXTableItem* item,FXint how)
50 {
51  if(item==0) {
52  editEnd();
53  return;
54  }
55  if(myWriteProtectedCols.find(myEditedCol)!=myWriteProtectedCols.end()) {
56  editEnd();
57  return;
58  }
59  FXTableItem* it= item;
60  myPreviousText = item->getText();
61  FXint x = getColumnX(myEditedCol) + getRowHeader()->getWidth() + xpos;
62  FXint y = getRowY(myEditedRow) + getColumnHeader()->getHeight() + ypos;
63  FXIcon* icon = item->getIcon();
64  if(icon) x += icon->getWidth() + 4;
65  FXint vw = getViewportWidth();
66  if(vertical->shown()) vw -= vertical->getWidth();
67  if(vw>getColumnWidth(myEditedCol)) {
68  vw = getColumnWidth(myEditedCol) + x;
69  }
70  switch(getCellType(myEditedCol)) {
71  case CT_UNDEFINED:
72  case CT_STRING:
73  myEditor->setText(it->getText());
74  myEditor->move(x, y);
75  myEditor->resize(vw - x + 1, getRowHeight(myEditedRow) + 1);
76  myEditor->show();
77  myEditor->raise();
78  myEditor->enable();
79  myEditor->setFocus();
80  myEditor->grab();
81  if(how == 'I') {
82  myEditor->killSelection();
83  myEditor->setCursorPos(0);
84  } else if(how == 'A') {
85  myEditor->killSelection();
86  myEditor->setCursorPos(myEditor->getText().length());
87  } else myEditor->selectAll();
88  break;
89  case CT_REAL:
90  {
91  try {
92  myNumberEditor->setValue(
93  TplConvert::_2double(it->getText().text()));
94  } catch (NumberFormatException &) {
95  } catch (EmptyData &) {
96  }
97  NumberCellParams p = getNumberCellParams(myEditedCol);
98  if(p.format!="undefined") {
99  myNumberEditor->setFormatString((char*) p.format.c_str());
100  myNumberEditor->setIncrements(p.steps1, p.steps2, p.steps3);
101  myNumberEditor->setRange(p.min, p.max);
102  }
103  myNumberEditor->move(x, y);
104  myNumberEditor->resize(vw - x + 1, getRowHeight(myEditedRow) + 1);
105  myNumberEditor->show();
106  myNumberEditor->raise();
107  myNumberEditor->setFocus();
108  myNumberEditor->selectAll();
109  }
110  //myNumberEditor->setRange(0,1000);
111  break;
112  case CT_INT:
113  {
114  try {
115  myNumberEditor->setValue(
116  TplConvert::_2int(it->getText().text()));
117  } catch (NumberFormatException &) {
118  } catch (EmptyData &) {
119  }
120  NumberCellParams p = getNumberCellParams(myEditedCol);
121  if(p.format!="undefined") {
122  myNumberEditor->setFormatString((char*) p.format.c_str());
123  myNumberEditor->setIncrements(p.steps1, p.steps2, p.steps3);
124  myNumberEditor->setRange(p.min, p.max);
125  }
126  myNumberEditor->move(x, y);
127  myNumberEditor->resize(vw - x + 1, getRowHeight(myEditedRow) + 1);
128  myNumberEditor->show();
129  myNumberEditor->raise();
130  myNumberEditor->setFocus();
131  myNumberEditor->selectAll();
132  }
133  break;
134  case CT_BOOL:
135  try {
136  myBoolEditor->setCheck(
137  TplConvert::_2bool(it->getText().text())
138  ? true : false);
139  } catch (NumberFormatException &) {
140  } catch (EmptyData &) {
141  }
142  myBoolEditor->move(x, y);
143  myBoolEditor->resize(vw - x + 1, getRowHeight(myEditedRow) + 1);
144  myBoolEditor->show();
145  myBoolEditor->raise();
146  myBoolEditor->setFocus();
147  break;
148  case CT_ENUM:
149  {
150  myEnumEditor->hide();
151  myEnumEditor->clearItems();
152  if(myEnums.size()>myEditedCol) {
153  for(int i=0; i<myEnums[myEditedCol].size(); i++) {
154  myEnumEditor->appendItem(myEnums[myEditedCol][i].c_str());
155  }
156  }
157  if(myEnumEditor->findItem(it->getText())>=0) {
158  myEnumEditor->setCurrentItem(
159  myEnumEditor->findItem(it->getText()));
160  } else {
161  myEnumEditor->setCurrentItem(0);
162  }
163  myEnumEditor->setNumVisible(
164  myEnums[myEditedCol].size()<10
165  ? myEnums[myEditedCol].size()
166  : 10);
167  myEnumEditor->layout();
168  y = getRowY(myEditedRow) + getColumnHeader()->getHeight() + ypos
169  - getRowHeight(myEditedRow);
170  myEnumEditor->move(x, y);
171  myEnumEditor->resize(vw - x + 1, getRowHeight(myEditedRow) + 1);
172  myEnumEditor->show();
173  myEnumEditor->raise();
174  myEnumEditor->setFocus();
175  }
176  break;
177  default:
178  throw 1;
179  }
180  myEditedItem = it;
181 }
182 */
183 
184 
185 FXWindow*
187  FXTableItem* item = cells[r * ncols + c];
188  if (item == nullptr) {
189  return nullptr;
190 // cells[r * ncols + c] = item = createItem("", NULL, NULL);
191 // if (isItemSelected(r, c)) {
192 // item->setSelected(FALSE);
193 // }
194  }
195  delete editor;
196  editor = nullptr;
197  switch (getCellType(c)) {
198  case CT_UNDEFINED:
199  case CT_STRING: {
200  FXTextField* field;
201  FXuint justify = 0;
202  field = new FXTextField(this, 1, nullptr, 0, TEXTFIELD_ENTER_ONLY, 0, 0, 0, 0, getMarginLeft(), getMarginRight(), getMarginTop(), getMarginBottom());
203  // !!! if(state&LEFT) justify|=JUSTIFY_LEFT;
204  // !!! if(state&RIGHT) justify|=JUSTIFY_RIGHT;
205  // !!! if(state&TOP) justify|=JUSTIFY_TOP;
206  // !!! if(state&BOTTOM) justify|=JUSTIFY_BOTTOM;
207  field->create();
208  field->setJustify(justify);
209  field->setFont(getFont());
210  field->setBackColor(getBackColor());
211  field->setTextColor(getTextColor());
212  field->setSelBackColor(getSelBackColor());
213  field->setSelTextColor(getSelTextColor());
214  field->setText(item->getText());
215  field->selectAll();
216  return field;
217  }
218  case CT_REAL:
219 // return myNumberEditor;
220  case CT_INT: {
221  FXRealSpinner* field;
222  //FXuint justify=0;
223  field = new FXRealSpinner(this, 1, nullptr, 0, TEXTFIELD_ENTER_ONLY, 0, 0, 0, 0, getMarginLeft(), getMarginRight(), getMarginTop(), getMarginBottom());
224  // !!! if(state&LEFT) justify|=JUSTIFY_LEFT;
225  // !!! if(state&RIGHT) justify|=JUSTIFY_RIGHT;
226  // !!! if(state&TOP) justify|=JUSTIFY_TOP;
227  // !!! if(state&BOTTOM) justify|=JUSTIFY_BOTTOM;
228  field->create();
229 // field->setJustify(justify);
230  field->setFont(getFont());
231  field->setBackColor(getBackColor());
232  field->setTextColor(getTextColor());
233  field->setSelBackColor(getSelBackColor());
234  field->setSelTextColor(getSelTextColor());
236  if (p.format != "undefined") {
237  //field->setFormatString((char*) p.format.c_str());
238  //field->setIncrements(p.steps1, p.steps2, p.steps3);
239  field->setIncrement(p.steps2);
240  field->setRange(p.min, p.max);
241  }
242  try {
243  if (getCellType(c) == CT_REAL) {
244  field->setValue(StringUtils::toDouble(item->getText().text()));
245  } else {
246  field->setValue(StringUtils::toInt(item->getText().text()));
247  }
248  } catch (NumberFormatException&) {
249  field->setValue(0);
250  }
251  //field->selectAll();
252  return field;
253  }
254  case CT_BOOL:
255 // return myBoolEditor;
256  case CT_ENUM:
257 // return myEnumEditor;
258  default:
259  throw 1;
260  }
261 }
262 
263 
264 // Cancel editing cell
265 void
267  if (editor) {
268  delete editor;
269  input.fm.row = -1;
270  input.to.row = -1;
271  input.fm.col = -1;
272  input.to.col = -1;
273  editor = nullptr;
274  }
275 }
276 
277 // Done with editing cell
278 void
280  bool set = false;
281  FXTableRange tablerange = input;
282  if (editor) {
283  FXRealSpinner* dial = dynamic_cast<FXRealSpinner*>(editor);
284  if (dial != nullptr) {
285  setItemFromControl_NoRelease(input.fm.row, input.fm.col, editor);
286  }
287  if (dynamic_cast<FXTextField*>(editor) != nullptr) {
288  set = true;
289  }
290  }
291  if (set) {
292  setItemFromControl(input.fm.row, input.fm.col, editor);
293  cancelInput();
294  if (notify && target) {
295  target->tryHandle(this, FXSEL(SEL_REPLACED, message), (void*)&tablerange);
296  }
297  }
298 }
299 
300 
301 
302 
303 void
304 MFXAddEditTypedTable::setItemFromControl(FXint r, FXint c, FXWindow* control) {
305  FXTableItem* item = cells[r * ncols + c];
306  if (item == nullptr) {
307  cells[r * ncols + c] = item = createItem("", nullptr, nullptr);
308  if (isItemSelected(r, c)) {
309  item->setSelected(FALSE);
310  }
311  }
312  switch (getCellType(c)) {
313  case CT_UNDEFINED:
314  case CT_STRING:
315  item->setFromControl(control);
316  break;
317  case CT_REAL:
318  item->setText(toString(static_cast<FXRealSpinner*>(control)->getValue()).c_str());
319  break;
320  case CT_INT:
321  item->setText(toString((int) static_cast<FXRealSpinner*>(control)->getValue()).c_str());
322  break;
323  case CT_BOOL:
324 // return myBoolEditor;
325  case CT_ENUM:
326 // return myEnumEditor;
327  default:
328  throw 1;
329  }
330 // current.row = -1;
331 // current.col = -1;
332  EditedTableItem edited;
333  edited.item = item;
334  edited.row = r;
335  edited.col = c;
336  edited.updateOnly = false;
337  killSelection(true);
338  bool accepted = true;
339  if (target) {
340  if (!target->handle(this, FXSEL(SEL_CHANGED, ID_TEXT_CHANGED), (void*) &edited)) {
341  accepted = false;
342  // !!! item->setText(myPreviousText);
343  }
344  }
345  if (accepted) {
346  if (edited.row == getNumRows() - 1) {
347  insertRows(getNumRows(), 1, true);
348  for (int i = 0; i < getNumColumns(); i++) {
349  setItemText(getNumRows() - 1, i, "");
350  setItemJustify(getNumRows() - 1, i, JUSTIFY_CENTER_X);
351  }
352  }
353  }
354  mode = MOUSE_NONE;
355 }
356 
357 
358 void
359 MFXAddEditTypedTable::setItemFromControl_NoRelease(FXint r, FXint c, FXWindow* control) {
360  FXTableItem* item = cells[r * ncols + c];
361  if (item == nullptr) {
362  return;
363  }
364  switch (getCellType(c)) {
365  case CT_UNDEFINED:
366  case CT_STRING:
367  item->setFromControl(control);
368  break;
369  case CT_REAL:
370  item->setText(toString(static_cast<FXRealSpinner*>(control)->getValue()).c_str());
371  break;
372  case CT_INT:
373  item->setText(toString((int) static_cast<FXRealSpinner*>(control)->getValue()).c_str());
374  break;
375  case CT_BOOL:
376 // return myBoolEditor;
377  case CT_ENUM:
378 // return myEnumEditor;
379  default:
380  throw 1;
381  }
382  EditedTableItem edited;
383  edited.item = item;
384  edited.row = r;
385  edited.col = c;
386  edited.updateOnly = true;
387  if (target) {
388  if (!target->handle(this, FXSEL(SEL_CHANGED, ID_TEXT_CHANGED), (void*) &edited)) {
389  // !!! item->setText(myPreviousText);
390  }
391  }
392 }
393 
394 
395 // Released button
396 long MFXAddEditTypedTable::onLeftBtnRelease(FXObject*, FXSelector, void* ptr) {
397  FXEvent* event = (FXEvent*)ptr;
398  if (isEnabled()) {
399  ungrab();
400  flags &= ~FLAG_PRESSED;
401  flags |= FLAG_UPDATE;
402  mode = MOUSE_NONE;
403  stopAutoScroll();
404  setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
405  if (target && target->tryHandle(this, FXSEL(SEL_LEFTBUTTONRELEASE, message), ptr)) {
406  return 1;
407  }
408 
409  // Scroll to make item visibke
410  makePositionVisible(current.row, current.col);
411 
412  // Update anchor
413  //setAnchorItem(current.row,current.col); // FIXME look into the selection stuff
414 
415  // Generate clicked callbacks
416  if (event->click_count == 1) {
417  handle(this, FXSEL(SEL_CLICKED, 0), (void*)&current);
418  } else if (event->click_count == 2) {
419  handle(this, FXSEL(SEL_DOUBLECLICKED, 0), (void*)&current);
420  } else if (event->click_count == 3) {
421  handle(this, FXSEL(SEL_TRIPLECLICKED, 0), (void*)&current);
422  }
423 
424  // Command callback only when clicked on item
425  if (0 <= current.row && 0 <= current.col && isItemEnabled(current.row, current.col)) {
426  handle(this, FXSEL(SEL_COMMAND, 0), (void*)&current);
427  }
428  return 1;
429  }
430  return 0;
431 }
432 
433 
434 // Pressed button
435 long
436 MFXAddEditTypedTable::onLeftBtnPress(FXObject*, FXSelector, void* ptr) {
437  FXEvent* event = (FXEvent*)ptr;
438  FXTablePos tablepos;
439  flags &= ~FLAG_TIP;
440  handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
441  if (isEnabled()) {
442  grab();
443  if (target && target->tryHandle(this, FXSEL(SEL_LEFTBUTTONPRESS, message), ptr)) {
444  return 1;
445  }
446 
447  // Cell being clicked on
448  tablepos.row = rowAtY(event->win_y);
449  tablepos.col = colAtX(event->win_x);
450 
451  // Outside table
452  if (tablepos.row < 0 || tablepos.row >= nrows || tablepos.col < 0 || tablepos.col >= ncols) {
453  setCurrentItem(-1, -1, TRUE);
454  return 0;
455  }
456 
457  // Change current item
458  bool wasEdited = editor != nullptr;
459  setCurrentItem(tablepos.row, tablepos.col, TRUE);
460  if (!wasEdited) {
461 
462  // Select or deselect
463  if (event->state & SHIFTMASK) {
464  if (0 <= anchor.row && 0 <= anchor.col) {
465  if (isItemEnabled(anchor.row, anchor.col)) {
466  extendSelection(current.row, current.col, TRUE);
467  }
468  } else {
469  setAnchorItem(current.row, current.col);
470  if (isItemEnabled(current.row, current.col)) {
471  extendSelection(current.row, current.col, TRUE);
472  }
473  }
474  mode = MOUSE_SELECT;
475  } else {
476  if (isItemEnabled(current.row, current.col)) {
477  killSelection(TRUE);
478  setAnchorItem(current.row, current.col);
479  extendSelection(current.row, current.col, TRUE);
480  } else {
481  setAnchorItem(current.row, current.col);
482  }
483  mode = MOUSE_SELECT;
484  }
485  }
486  flags &= ~FLAG_UPDATE;
487  flags |= FLAG_PRESSED;
488  return 1;
489  }
490  return 0;
491 }
492 
493 
494 
495 // Clicked in list
496 long
497 MFXAddEditTypedTable::onClicked(FXObject*, FXSelector, void* ptr) {
498  if (editor) {
499  delete editor;
500  input.fm.row = -1;
501  input.to.row = -1;
502  input.fm.col = -1;
503  input.to.col = -1;
504  editor = nullptr;
505  current.row = -1;
506  current.col = -1;
507  }
508  if (target && target->tryHandle(this, FXSEL(SEL_CLICKED, message), ptr)) {
509  return 1;
510  }
511  handle(this, FXSEL(SEL_COMMAND, ID_START_INPUT), nullptr);
512  return 1;
513 }
514 
515 
516 // Double clicked in list; ptr may or may not point to an item
517 long MFXAddEditTypedTable::onDoubleClicked(FXObject*, FXSelector, void* ptr) {
518  if (editor) {
519  delete editor;
520  input.fm.row = -1;
521  input.to.row = -1;
522  input.fm.col = -1;
523  input.to.col = -1;
524  editor = nullptr;
525  } else {
526  if (target && target->tryHandle(this, FXSEL(SEL_CLICKED, message), ptr)) {
527  return 1;
528  }
529  handle(this, FXSEL(SEL_COMMAND, ID_START_INPUT), nullptr);
530  }
531  return 1;
532 }
533 
534 
535 CellType
537  if ((int)myCellTypes.size() <= pos) {
538  return CT_UNDEFINED;
539  }
540  return myCellTypes[pos];
541 }
542 
543 
544 void
546  while ((int)myCellTypes.size() < pos + 1) {
547  myCellTypes.push_back(CT_UNDEFINED);
548  }
549  myCellTypes[pos] = t;
550 }
551 
552 void
553 MFXAddEditTypedTable::setNumberCellParams(int pos, double min, double max,
554  double steps1,
555  double steps2,
556  double steps3,
557  const std::string& format) {
558  while ((int)myNumberCellParams.size() <= pos) {
559  NumberCellParams np;
560  np.format = "undefined";
561  myNumberCellParams.push_back(np);
562  }
563  NumberCellParams np;
564  np.pos = (int)(pos);
565  np.min = min;
566  np.max = max;
567  np.steps1 = steps1;
568  np.steps2 = steps2;
569  np.steps3 = steps3;
570  np.format = format;
571  myNumberCellParams[pos] = np;
572 }
573 
574 
577  if ((int)myNumberCellParams.size() <= pos) {
578  NumberCellParams np;
579  np.format = "undefined";
580  return np;
581  }
582  return myNumberCellParams[pos];
583 }
584 
585 
586 
587 void
589  const std::vector<std::string>& params) {
590  while ((int)myEnums.size() <= pos) {
591  myEnums.push_back(std::vector<std::string>());
592  }
593  myEnums[pos] = params;
594 }
595 
596 
597 void
599  const std::string& e) {
600  while ((int)myEnums.size() <= pos) {
601  myEnums.push_back(std::vector<std::string>());
602  }
603  myEnums[pos].push_back(e);
604 }
605 
606 
607 const std::vector<std::string>&
609  return myEnums[pos];
610 }
611 
612 
613 /****************************************************************************/
FXDEFMAP(MFXAddEditTypedTable) MFXAddEditTypedTableMap[]
@ CT_UNDEFINED
@ CT_STRING
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
std::vector< std::vector< std::string > > myEnums
virtual FXWindow * getControlForItem(FXint r, FXint c)
std::vector< NumberCellParams > myNumberCellParams
long onClicked(FXObject *, FXSelector, void *ptr)
long onLeftBtnRelease(FXObject *, FXSelector, void *ptr)
void addEnum(int pos, const std::string &e)
long onDoubleClicked(FXObject *, FXSelector, void *ptr)
void setCellType(int pos, CellType t)
NumberCellParams getNumberCellParams(int pos) const
void setNumberCellParams(int pos, double min, double max, double steps1, double steps2, double steps3, const std::string &format)
void setItemFromControl_NoRelease(FXint r, FXint c, FXWindow *control)
void setEnums(int pos, const std::vector< std::string > &params)
long onLeftBtnPress(FXObject *, FXSelector, void *ptr)
void acceptInput(FXbool notify)
CellType getCellType(int pos) const
virtual void setItemFromControl(FXint r, FXint c, FXWindow *control)
const std::vector< std::string > & getEnums(int pos) const
std::vector< CellType > myCellTypes
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...