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