Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GNETLSTable.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// Table used in GNETLSFrame for editing TLS programs
19/****************************************************************************/
20
22#include <netedit/GNEViewNet.h>
31
32#include "GNETLSTable.h"
33
34// ===========================================================================
35// Defines
36// ===========================================================================
37
38#define EXTRAMARGIN 1
39#define DEFAULTWIDTH 190
40
41// ===========================================================================
42// FOX callback mapping
43// ===========================================================================
44
45FXDEFMAP(GNETLSTable) GNETLSTableMap[] = {
48 // text fields
52 // add phase buttons
59 // remove phase button
62 // move up phase button
65 // move down phase button
68};
69
70// Object implementation
71FXIMPLEMENT(GNETLSTable, FXHorizontalFrame, GNETLSTableMap, ARRAYNUMBER(GNETLSTableMap))
72
73// ===========================================================================
74// method definitions
75// ===========================================================================
76
77// ---------------------------------------------------------------------------
78// GNETLSTable - public methods
79// ---------------------------------------------------------------------------
80
81GNETLSTable::GNETLSTable(GNETLSEditorFrame::TLSPhases* TLSPhasesParent) :
82 FXHorizontalFrame(TLSPhasesParent->getCollapsableFrame(), GUIDesignAuxiliarFrameFixedWidth(0)),
83 myProgramFont(new FXFont(getApp(), "Courier New", 10)),
84 myIndexFont(new FXFont(getApp(), "Segoe UI", 9)),
85 myIndexSelectedFont(new FXFont(getApp(), "Segoe UI", 9, FXFont::Bold)),
86 myTLSPhasesParent(TLSPhasesParent) {
87 // set default width
88 recalcTableWidth();
89}
90
91
93 // delete fonts
94 delete myProgramFont;
95 delete myIndexFont;
97}
98
99
100void
102 // enable all cells
103 for (const auto& row : myRows) {
104 for (const auto& cell : row->getCells()) {
105 cell->enable();
106 }
107 }
108 // enable horizontal frame
109 FXHorizontalFrame::enable();
110}
111
112
113void
115 // disable all cells
116 for (const auto& row : myRows) {
117 for (const auto& cell : row->getCells()) {
118 cell->disable();
119 }
120 }
121 // disable horizontal frame
122 FXHorizontalFrame::disable();
123}
124
125
130
131
132void
134 // get minimum width of all elements
135 int minimumTableWidth = 0;
136 // get pointer to name column
137 Column* nameColumn = nullptr;
138 // iterate over all columns
139 for (const auto& column : myColumns) {
140 // check if this is the name column
141 if (column->getType() == 'm') {
142 // save column
143 nameColumn = column;
144 } else {
145 // get minimum column width
146 const auto minimunColWidth = column->getColumnMinimumWidth();
147 // set columnwidth
148 column->setColumnWidth(minimunColWidth);
149 // update minimum table width
150 minimumTableWidth += minimunColWidth;
151 }
152 }
153 // adjust name column
154 if (nameColumn) {
155 // get column name width
156 const int minimumColNameWidth = nameColumn->getColumnMinimumWidth();
157 // get scrollBar width
158 const int scrollBarWidth = myTLSPhasesParent->getTLSEditorParent()->getScrollBarWidth();
159 // get frame area width - padding (30, constant, 15 left, 15 right)
160 const auto frameAreaWidth = myTLSPhasesParent->getTLSEditorParent()->getViewNet()->getViewParent()->getFrameAreaWidth() - 30;
161 // continue depending of minimum table width
162 if ((frameAreaWidth - (minimumTableWidth + minimumColNameWidth + scrollBarWidth)) > 0) {
163 nameColumn->setColumnWidth(frameAreaWidth - minimumTableWidth - scrollBarWidth);
164 setWidth(frameAreaWidth);
165 } else {
166 nameColumn->setColumnWidth(minimumColNameWidth);
167 setWidth(minimumTableWidth + minimumColNameWidth);
168 }
169 } else if (minimumTableWidth > 0) {
170 setWidth(minimumTableWidth);
171 } else {
172 setWidth(DEFAULTWIDTH);
173 }
174}
175
176
177void
179 // clear rows (always before columns, because delete row delete also all cells)
180 for (const auto& row : myRows) {
181 delete row;
182 }
183 // clear columns
184 for (const auto& column : myColumns) {
185 delete column;
186 }
187 // drop rows and columns
188 myRows.clear();
189 myColumns.clear();
190}
191
192
193void
194GNETLSTable::setTableSize(const std::string& columnsType, const int numberRow) {
195 // first clear table
196 clearTable();
197 // create columns
198 for (int i = 0; i < (FXint)columnsType.size(); i++) {
199 myColumns.push_back(new Column(this, i, columnsType.at(i)));
200 }
201 // create rows
202 for (int i = 0; i < numberRow; i++) {
203 myRows.push_back(new Row(this));
204 }
205 // if we have only a row, disable remove and move buttons
206 if (myRows.size() == 1) {
207 myRows.front()->disableButtons();
208 }
209}
210
211
212void
213GNETLSTable::setItemText(FXint row, FXint column, const std::string& text) {
214 if ((row >= 0) && (row < (FXint)myRows.size()) &&
215 (column >= 0) && (column < (FXint)myColumns.size())) {
216 myRows.at(row)->setText(column, text);
217 // check if update accumulated duration
218 if (myColumns.at(column)->getType() == 'u') {
220 }
221 } else {
222 throw ProcessError(TL("Invalid row or column"));
223 }
224}
225
226
227std::string
228GNETLSTable::getItemText(const int row, const int column) const {
229 if ((row >= 0) && (row < (FXint)myRows.size()) &&
230 (column >= 0) && (column < (FXint)myColumns.size())) {
231 return myRows.at(row)->getText(column);
232 }
233 throw ProcessError(TL("Invalid row or column"));
234}
235
236
237int
239 return (int)myRows.size();
240}
241
242
243int
247
248
249void
251 if ((row >= 0) && (row < (FXint)myRows.size())) {
252 // update current selected row
254 // update index label
256 } else {
257 throw ProcessError(TL("Invalid row"));
258 }
259}
260
261
262void
263GNETLSTable::setColumnLabelTop(const int column, const std::string& text, const std::string& tooltip) {
264 if ((column >= 0) && (column < (int)myColumns.size())) {
265 myColumns.at(column)->setColumnLabelTop(text, tooltip);
266 } else {
267 throw ProcessError(TL("Invalid column"));
268 }
269}
270
271
272void
273GNETLSTable::setColumnLabelBot(const int column, const std::string& text) {
274 if ((column >= 0) && (column < (int)myColumns.size())) {
275 myColumns.at(column)->setColumnLabelBot(text);
276 } else {
277 throw ProcessError(TL("Invalid column"));
278 }
279}
280
281
282long
284 // obtain cell
285 if (tableTest->row >= (int)myRows.size()) {
286 throw ProcessError(TL("Invalid row in table test"));
287 } else if (tableTest->column >= (int)myColumns.size()) {
288 throw ProcessError(TL("Invalid column in table test"));
289 } else {
290 // get cell
291 Cell* cell = myRows.at(tableTest->row)->getCells().at(tableTest->column);
292 // continue depending of operation
293 if (tableTest->sel == MID_GNE_TLSTABLE_ADDPHASE) {
294 return onCmdAddPhase(cell->getAddPhaseButton(), 0, nullptr);
295 } else if (tableTest->sel == MID_GNE_TLSTABLE_COPYPHASE) {
296 return onCmdDuplicatePhase(cell->getDuplicatePhaseButton(), 0, nullptr);
297 } else if (tableTest->sel == MID_GNE_TLSTABLE_ADDPHASEALLRED) {
298 return onCmdAddPhaseAllRed(cell->getAddAllRedPhaseButton(), 0, nullptr);
299 } else if (tableTest->sel == MID_GNE_TLSTABLE_ADDPHASEALLYELLOW) {
300 return onCmdAddPhaseAllYellow(cell->getAddAllYellowPhaseButton(), 0, nullptr);
301 } else if (tableTest->sel == MID_GNE_TLSTABLE_ADDPHASEALLGREEN) {
302 return onCmdAddPhaseAllGreen(cell->getAddAllGreenPhaseButton(), 0, nullptr);
303 } else if (tableTest->sel == MID_GNE_TLSTABLE_ADDPHASEALLGREENPRIORITY) {
305 } else if (tableTest->sel == MID_GNE_TLSTABLE_REMOVEPHASE) {
306 return onCmdRemovePhase(cell->getButton(), 0, nullptr);
307 } else if (tableTest->sel == MID_GNE_TLSTABLE_MOVEUPPHASE) {
308 return onCmdMoveUpPhase(cell->getButton(), 0, nullptr);
309 } else if (tableTest->sel == MID_GNE_TLSTABLE_MOVEDOWNPHASE) {
310 return onCmdMoveDownPhase(cell->getButton(), 0, nullptr);
311 } else if (tableTest->sel == MID_GNE_TLSTABLE_TEXTFIELD) {
312 // set text in text field
313 cell->getTextField()->setText(tableTest->text.c_str(), TRUE);
314 return 1;
315 } else {
316 // unknown operation
317 throw ProcessError(TL("Unknown operation in table test"));
318 }
319 }
320}
321
322
323long
324GNETLSTable::onFocusRow(FXObject* sender, FXSelector, void*) {
325 int selectedRow = -1;
326 // search selected text field
327 for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
328 // iterate over every cell
329 for (const auto& cell : myRows.at(rowIndex)->getCells()) {
330 if ((cell->getTextField() == sender) || (cell->getAddButton() == sender)) {
331 selectedRow = rowIndex;
332 }
333 }
334 }
335 // update index label
337 // set new row
338 if (myCurrentSelectedRow != selectedRow) {
339 myCurrentSelectedRow = selectedRow;
341 }
342 return 0;
343}
344
345
346long
347GNETLSTable::onCmdAddPhasePressed(FXObject* sender, FXSelector, void*) {
348 // search selected add button
349 for (int columnIndex = 0; columnIndex < (int)myColumns.size(); columnIndex++) {
350 for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
351 if (myRows.at(rowIndex)->getCells().at(columnIndex)->getAddButton() == sender) {
352 myRows.at(rowIndex)->getCells().at(columnIndex)->getAddPhaseButton()->setFocus();
353 return 1;
354 }
355 }
356 }
357 // nothing to focus
358 return 0;
359}
360
361
362long
363GNETLSTable::onCmdEditRow(FXObject* sender, FXSelector, void*) {
364 // search selected text field
365 for (int columnIndex = 0; columnIndex < (int)myColumns.size(); columnIndex++) {
366 for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
367 // get text field
368 const auto textField = myRows.at(rowIndex)->getCells().at(columnIndex)->getTextField();
369 if (textField == sender) {
370 // edit value and change value depending of result
371 if (myTLSPhasesParent->changePhaseValue(columnIndex, rowIndex, textField->getText().text())) {
372 textField->setTextColor(GUIDesignTextColorBlack);
373 textField->killFocus();
375 } else {
376 textField->setTextColor(GUIDesignTextColorRed);
377 }
378 return 1;
379 }
380 }
381 }
382 // nothing to edit
383 return 0;
384}
385
386
387long
388GNETLSTable::onCmdKeyPress(FXObject* sender, FXSelector sel, void* ptr) {
389 // get FXEvent
390 FXEvent* eventInfo = (FXEvent*)ptr;
391 // check code
392 if (eventInfo->code == 65362) {
393 // move up
394 if (myCurrentSelectedRow > 0) {
396 } else {
397 // we're in the first, then select last
398 myCurrentSelectedRow = ((int)myRows.size() - 1);
399 }
400 // update index label
402 // move focus
403 moveFocus();
404 return 1;
405 } else if (eventInfo->code == 65364) {
406 // move down
407 if (myCurrentSelectedRow < ((int)myRows.size() - 1)) {
409 } else {
410 // we're in the last, then select first
412 }
413 // update index label
415 // move focus
416 moveFocus();
417 return 1;
418 } else {
419 // continue handling key pres
420 return sender->handle(sender, sel, ptr);
421 }
422}
423
424
425long
426GNETLSTable::onCmdAddPhase(FXObject* sender, FXSelector, void*) {
427 // search selected text field
428 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
429 // iterate over every cell
430 for (const auto& cell : myRows.at(indexRow)->getCells()) {
431 if (cell->getAddPhaseButton() == sender) {
432 // hide popup
433 cell->hideMenuButtonPopup();
434 // add row
435 myTLSPhasesParent->addPhase(indexRow);
436 // stop
437 return 0;
438 }
439 }
440 }
441 return 0;
442}
443
444
445long
446GNETLSTable::onCmdDuplicatePhase(FXObject* sender, FXSelector, void*) {
447 // search selected text field
448 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
449 // iterate over every cell
450 for (const auto& cell : myRows.at(indexRow)->getCells()) {
451 if (cell->getDuplicatePhaseButton() == sender) {
452 // hide popup
453 cell->hideMenuButtonPopup();
454 // duplicate row
456 // stop
457 return 0;
458 }
459 }
460 }
461 return 0;
462}
463
464
465long
466GNETLSTable::onCmdAddPhaseAllRed(FXObject* sender, FXSelector, void*) {
467 // search selected text field
468 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
469 // iterate over every cell
470 for (const auto& cell : myRows.at(indexRow)->getCells()) {
471 if (cell->getAddAllRedPhaseButton() == sender) {
472 // hide popup
473 cell->hideMenuButtonPopup();
474 // add row
475 myTLSPhasesParent->addPhase(indexRow, 'r');
476 // stop
477 return 0;
478 }
479 }
480 }
481 return 0;
482}
483
484
485long
486GNETLSTable::onCmdAddPhaseAllYellow(FXObject* sender, FXSelector, void*) {
487 // search selected text field
488 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
489 // iterate over every cell
490 for (const auto& cell : myRows.at(indexRow)->getCells()) {
491 if (cell->getAddAllYellowPhaseButton() == sender) {
492 // hide popup
493 cell->hideMenuButtonPopup();
494 // add row
495 myTLSPhasesParent->addPhase(indexRow, 'y');
496 // stop
497 return 0;
498 }
499 }
500 }
501 return 0;
502}
503
504
505long
506GNETLSTable::onCmdAddPhaseAllGreen(FXObject* sender, FXSelector, void*) {
507 // search selected text field
508 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
509 // iterate over every cell
510 for (const auto& cell : myRows.at(indexRow)->getCells()) {
511 if (cell->getAddAllGreenPhaseButton() == sender) {
512 // hide popup
513 cell->hideMenuButtonPopup();
514 // add row
515 myTLSPhasesParent->addPhase(indexRow, 'g');
516 // stop
517 return 0;
518 }
519 }
520 }
521 return 0;
522}
523
524
525long
526GNETLSTable::onCmdAddPhaseAllGreenPriority(FXObject* sender, FXSelector, void*) {
527 // search selected text field
528 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
529 // iterate over every cell
530 for (const auto& cell : myRows.at(indexRow)->getCells()) {
531 if (cell->getAddAllGreenPriorityPhaseButton() == sender) {
532 // hide popup
533 cell->hideMenuButtonPopup();
534 // add row
535 myTLSPhasesParent->addPhase(indexRow, 'G');
536 // stop
537 return 0;
538 }
539 }
540 }
541 return 0;
542}
543
544
545long
546GNETLSTable::onCmdRemovePhase(FXObject* sender, FXSelector, void*) {
547 // search selected text field
548 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
549 // iterate over every cell
550 for (const auto& cell : myRows.at(indexRow)->getCells()) {
551 if (cell->getButton() == sender) {
552 // remove row
554 // stop
555 return 0;
556 }
557 }
558 }
559 return 0;
560}
561
562
563long
564GNETLSTable::onCmdMoveUpPhase(FXObject* sender, FXSelector, void*) {
565 // search selected text field
566 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
567 // iterate over every cell
568 for (const auto& cell : myRows.at(indexRow)->getCells()) {
569 if (cell->getButton() == sender) {
570 // move phase up
572 // stop
573 return 0;
574 }
575 }
576 }
577 return 0;
578}
579
580
581long
582GNETLSTable::onCmdMoveDownPhase(FXObject* sender, FXSelector, void*) {
583 // search selected text field
584 for (int indexRow = 0; indexRow < (int)myRows.size(); indexRow++) {
585 // iterate over every cell
586 for (const auto& cell : myRows.at(indexRow)->getCells()) {
587 if (cell->getButton() == sender) {
588 // move phase down
590 // stop
591 return 0;
592 }
593 }
594 }
595 return 0;
596}
597
598
599void
601 // update radio buttons checks
602 for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
603 // iterate over every cell
604 for (const auto& cell : myRows.at(rowIndex)->getCells()) {
605 if (cell->getIndexLabel()) {
606 if (myCurrentSelectedRow == rowIndex) {
607 cell->showIndexLabelBold();
608 } else {
609 cell->showIndexLabelNormal();
610 }
611 }
612 }
613 }
614 // update coloring
616}
617
618
619void
621 // first find the duration col
622 int durationCol = -1;
623 for (int i = 0; i < (int)myColumns.size(); i++) {
624 if (myColumns.at(i)->getType() == 'u') {
625 durationCol = i;
626 }
627 }
628 // continue depending of durationCol
629 if (durationCol != -1) {
630 // declare a int vector for saving durations
631 std::vector<double> durations;
632 // fill durations
633 for (const auto& row : myRows) {
634 durations.push_back(row->getCells().at(durationCol)->getDoubleValue());
635 }
636 // update durations
637 for (int i = 1; i < (int)durations.size(); i++) {
638 durations.at(i) += durations.at(i - 1);
639 }
640 // set tooltips in row cells
641 for (int i = 0; i < (int)myRows.size(); i++) {
642 myRows.at(i)->getCells().at(durationCol)->setTooltip(TL("Accumulated: ") + toString(durations.at(i)));
643 }
644 }
645}
646
647
648bool
650 // first find focus
651 // update radio buttons checks
652 for (int rowIndex = 0; rowIndex < (int)myRows.size(); rowIndex++) {
653 for (int cellIndex = 0; cellIndex < (int)myRows.at(rowIndex)->getCells().size(); cellIndex++) {
654 if (myRows.at(rowIndex)->getCells().at(cellIndex)->hasFocus()) {
655 // set focus in current row
656 myRows.at(myCurrentSelectedRow)->getCells().at(cellIndex)->setFocus();
657 return true;
658 }
659 }
660 }
661 return false;
662}
663
664// ---------------------------------------------------------------------------
665// GNETLSTable::Cell - methods
666// ---------------------------------------------------------------------------
667
668GNETLSTable::Cell::Cell(GNETLSTable* TLSTable, MFXTextFieldIcon* textField, int col, int row) :
669 myTLSTable(TLSTable),
670 myTextField(textField),
671 myCol(col),
672 myRow(row) {
673 // create
674 textField->create();
675}
676
677
678GNETLSTable::Cell::Cell(GNETLSTable* TLSTable, FXLabel* indexLabel, FXLabel* indexLabelBold, int col, int row) :
679 myTLSTable(TLSTable),
680 myIndexLabel(indexLabel),
681 myIndexLabelBold(indexLabelBold),
682 myCol(col),
683 myRow(row) {
684 // create both
685 indexLabel->create();
686 indexLabelBold->create();
687 // hide bold and set background
688 indexLabelBold->hide();
689 indexLabelBold->setBackColor(FXRGBA(210, 233, 255, 255));
690}
691
692
693GNETLSTable::Cell::Cell(GNETLSTable* TLSTable, MFXButtonTooltip* button, int col, int row) :
694 myTLSTable(TLSTable),
695 myButton(button),
696 myCol(col),
697 myRow(row) {
698 // create
699 button->create();
700}
701
702
703GNETLSTable::Cell::Cell(GNETLSTable* TLSTable, int col, int row) :
704 myTLSTable(TLSTable),
705 myCol(col),
706 myRow(row) {
707 // build locator popup
708 myMenuButtonPopup = new FXPopup(TLSTable->myColumns.at(col)->getVerticalCellFrame(), POPUP_HORIZONTAL);
709 // build menu button
710 myAddButton = new MFXMenuButtonTooltip(TLSTable->myColumns.at(col)->getVerticalCellFrame(),
712 (std::string("\t") + TL("Add phase") + std::string("\t") + TL("Add new phase.")).c_str(),
714 // default phase
717 (std::string("\t") + TL("Default phase") + std::string("\t") + TL("Add default phase.")).c_str(),
719 // duplicate phase
722 (std::string("\t") + TL("Duplicate phase") + std::string("\t") + TL("Duplicate this phase.")).c_str(),
724 // red phase
727 (std::string("\t") + TL("Red phase") + std::string("\t") + TL("Add red phase.")).c_str(),
729 // yellow phase
732 (std::string("\t") + TL("Yellow phase") + std::string("\t") + TL("Add yellow phase.")).c_str(),
734 // green phase
737 (std::string("\t") + TL("Green phase") + std::string("\t") + TL("Add green phase.")).c_str(),
739 // green priority phase
742 (std::string("\t") + TL("Green priority phase") + std::string("\t") + TL("Add green priority phase.")).c_str(),
744 // create elements
745 myMenuButtonPopup->create();
746 myAddButton->create();
747 myAddPhaseButton->create();
748 myDuplicatePhaseButton->create();
749 myAddAllRedButton->create();
750 myAddAllYellowButton->create();
751 myAddAllGreenButton->create();
753 // set backgrounds
754 myAddPhaseButton->setBackColor(FXRGBA(210, 233, 255, 255));
755 myDuplicatePhaseButton->setBackColor(FXRGBA(210, 233, 255, 255));
756 myAddAllRedButton->setBackColor(FXRGBA(255, 213, 213, 255));
757 myAddAllYellowButton->setBackColor(FXRGBA(253, 255, 206, 255));
758 myAddAllGreenButton->setBackColor(FXRGBA(240, 255, 205, 255));
759 myAddAllGreenPriorityButton->setBackColor(FXRGBA(240, 255, 205, 255));
760}
761
763 // delete all elements
764 if (myTextField) {
765 delete myTextField;
766 }
767 if (myIndexLabel) {
768 delete myIndexLabel;
769 }
770 if (myIndexLabelBold) {
771 delete myIndexLabelBold;
772 }
773 if (myButton) {
774 delete myButton;
775 }
776 if (myAddButton) {
777 delete myAddButton;
778 }
779 if (myAddPhaseButton) {
780 delete myAddPhaseButton;
781 }
782 if (myDuplicatePhaseButton) {
783 delete myDuplicatePhaseButton;
784 }
785 if (myAddAllRedButton) {
786 delete myAddAllRedButton;
787 }
788 if (myAddAllYellowButton) {
789 delete myAddAllYellowButton;
790 }
791 if (myAddAllGreenButton) {
792 delete myAddAllGreenButton;
793 }
794 if (myAddAllGreenPriorityButton) {
795 delete myAddAllGreenPriorityButton;
796 }
797 if (myMenuButtonPopup) {
798 delete myMenuButtonPopup;
799 }
800}
801
802void
804 // enable all elements
805 if (myTextField) {
806 myTextField->enable();
807 }
808 if (myIndexLabel) {
809 myIndexLabel->enable();
810 }
811 if (myIndexLabelBold) {
812 myIndexLabelBold->enable();
813 }
814 if (myButton && !myDisableButton) {
815 myButton->enable();
816 }
817 if (myAddButton) {
818 myAddButton->enable();
819 }
820 if (myAddPhaseButton) {
821 myAddPhaseButton->enable();
822 }
823 if (myDuplicatePhaseButton) {
824 myDuplicatePhaseButton->enable();
825 }
826 if (myAddAllRedButton) {
827 myAddAllRedButton->enable();
828 }
829 if (myAddAllYellowButton) {
830 myAddAllYellowButton->enable();
831 }
832 if (myAddAllGreenButton) {
833 myAddAllGreenButton->enable();
834 }
835 if (myAddAllGreenPriorityButton) {
836 myAddAllGreenPriorityButton->enable();
837 }
838 if (myMenuButtonPopup) {
839 myMenuButtonPopup->enable();
840 }
841}
842
843
844void
846 // disable all elements
847 if (myTextField) {
848 myTextField->disable();
849 }
850 if (myIndexLabel) {
851 myIndexLabel->disable();
852 }
853 if (myIndexLabelBold) {
854 myIndexLabelBold->disable();
855 }
856 if (myButton && !myDisableButton) {
857 myButton->disable();
858 }
859 if (myAddButton) {
860 myAddButton->disable();
861 }
862 if (myAddPhaseButton) {
863 myAddPhaseButton->disable();
864 }
865 if (myDuplicatePhaseButton) {
866 myDuplicatePhaseButton->disable();
867 }
868 if (myAddAllRedButton) {
869 myAddAllRedButton->disable();
870 }
871 if (myAddAllYellowButton) {
872 myAddAllYellowButton->disable();
873 }
874 if (myAddAllGreenButton) {
875 myAddAllGreenButton->disable();
876 }
877 if (myAddAllGreenPriorityButton) {
878 myAddAllGreenPriorityButton->disable();
879 }
880 if (myMenuButtonPopup) {
881 myMenuButtonPopup->disable();
882 }
883}
884
885
886bool
888 // check if one of the cell elements has the focus
889 if (myTextField && myTextField->hasFocus()) {
890 return true;
891 } else if (myButton && myButton->hasFocus()) {
892 return true;
893 } else if (myAddButton && myAddButton->hasFocus()) {
894 return true;
895 } else if (myAddPhaseButton && myAddPhaseButton->hasFocus()) {
896 return true;
897 } else if (myDuplicatePhaseButton && myDuplicatePhaseButton->hasFocus()) {
898 return true;
899 } else if (myAddAllRedButton && myAddAllRedButton->hasFocus()) {
900 return true;
901 } else if (myAddAllYellowButton && myAddAllYellowButton->hasFocus()) {
902 return true;
903 } else if (myAddAllGreenButton && myAddAllGreenButton->hasFocus()) {
904 return true;
905 } else if (myAddAllGreenPriorityButton && myAddAllGreenPriorityButton->hasFocus()) {
906 return true;
907 } else {
908 return false;
909 }
910}
911
912
913void
915 // set focus
916 if (myTextField) {
917 myTextField->setFocus();
918 } else if (myButton) {
919 myButton->setFocus();
920 } else if (myAddButton) {
921 myAddButton->setFocus();
922 } else if (myAddPhaseButton) {
923 myAddPhaseButton->setFocus();
924 } else if (myDuplicatePhaseButton) {
925 myDuplicatePhaseButton->setFocus();
926 } else if (myAddAllRedButton) {
927 myAddAllRedButton->setFocus();
928 } else if (myAddAllYellowButton) {
929 myAddAllYellowButton->setFocus();
930 } else if (myAddAllGreenButton) {
931 myAddAllGreenButton->setFocus();
932 } else if (myAddAllGreenPriorityButton) {
933 myAddAllGreenPriorityButton->setFocus();
934 }
935}
936
937
938double
940 if (myTextField->getText().empty()) {
941 return 0;
942 } else if (!GNEAttributeCarrier::canParse<double>(myTextField->getText().text())) {
943 throw ProcessError(TL("Cannot be parsed to double"));
944 } else {
945 return GNEAttributeCarrier::parse<double>(myTextField->getText().text());
946 }
947}
948
949
950void
951GNETLSTable::Cell::setTooltip(const std::string& toolTip) {
952 if (myTextField) {
953 myTextField->setToolTipText(toolTip.c_str());
954 } else {
955 throw ProcessError(TL("Tooltips only for TextFields"));
956 }
957}
958
959
962 return myTextField;
963}
964
965
966FXLabel*
968 return myIndexLabel;
969}
970
971
974 return myAddButton;
975}
976
977
980 return myButton;
981}
982
983
986 return myAddPhaseButton;
987}
988
989
992 return myDuplicatePhaseButton;
993}
994
995
998 return myAddAllRedButton;
999}
1000
1001
1004 return myAddAllYellowButton;
1005}
1006
1007
1010 return myAddAllGreenButton;
1011}
1012
1013
1016 return myAddAllGreenPriorityButton;
1017}
1018
1019
1020void
1022 myIndexLabel->show();
1023 myIndexLabelBold->hide();
1024 // recalc both
1025 myIndexLabel->recalc();
1026 myIndexLabelBold->recalc();
1027}
1028
1029
1030void
1032 myIndexLabel->hide();
1033 myIndexLabelBold->show();
1034 // recalc both
1035 myIndexLabel->recalc();
1036 myIndexLabelBold->recalc();
1037}
1038
1039
1040int
1042 return myCol;
1043}
1044
1045
1046int
1048 return myRow;
1049}
1050
1051
1052char
1054 return myTLSTable->myColumns.at(myCol)->getType();
1055}
1056
1057
1058void
1060 if (myMenuButtonPopup) {
1061 myMenuButtonPopup->popdown();
1062 }
1063}
1064
1065
1066void
1068 if (myButton) {
1069 myButton->disable();
1070 myDisableButton = true;
1071 }
1072}
1073
1074
1076 myCol(-1),
1077 myRow(-1) {
1078}
1079
1080// ---------------------------------------------------------------------------
1081// GNETLSTable::Column - methods
1082// ---------------------------------------------------------------------------
1083
1084GNETLSTable::Column::Column(GNETLSTable* table, const int index, const char type) :
1085 myTable(table),
1086 myIndex(index),
1087 myType(type) {
1088 // create vertical frame
1089 myVerticalFrame = new FXVerticalFrame(table, GUIDesignAuxiliarFrameFixedWidth(0));
1090 // create top label
1091 switch (myType) {
1092 case 's':
1093 case 'i':
1094 case 'd':
1095 case 't':
1096 case 'b':
1097 // empty label
1100 "", nullptr, GUIDesignLabelFixed(0));
1101 break;
1102 default:
1103 // ticked label
1106 "", nullptr, GUIDesignLabelThickedFixed(0));
1107 break;
1108 }
1109 // create vertical frame for cells
1111 // create bot label
1112 switch (myType) {
1113 case 's':
1114 // label with icon
1116 break;
1117 case 'u':
1118 case 'p':
1119 // ticked label
1120 myBotLabel = new FXLabel(myVerticalFrame, "", nullptr, GUIDesignLabelThickedFixed(0));
1121 break;
1122 default:
1123 // empty label
1124 myBotLabel = new FXLabel(myVerticalFrame, "", nullptr, GUIDesignLabelFixed(0));
1125 break;
1126 }
1127 // create elements
1128 myVerticalFrame->create();
1129 myTopLabel->create();
1130 myVerticalCellFrame->create();
1131 myBotLabel->create();
1132}
1133
1134
1136 // delete vertical frame (this also delete all childrens)
1137 delete myVerticalFrame;
1138}
1139
1140
1141FXVerticalFrame*
1143 return myVerticalCellFrame;
1144}
1145
1146
1147char
1149 return myType;
1150}
1151
1152
1153FXString
1155 return myTopLabel->getText();
1156}
1157
1158
1159void
1160GNETLSTable::Column::setColumnLabelTop(const std::string& text, const std::string& tooltip) {
1161 myTopLabel->setText(text.c_str());
1162 myTopLabel->setTipText(tooltip.c_str());
1163}
1164
1165
1166void
1168 myBotLabel->setText(text.c_str());
1169}
1170
1171
1172int
1174 // declare columnWidth
1175 int columnWidth = 0;
1176 // check column type
1177 if (myType == 's') {
1178 // set index column width
1179 columnWidth = 30;
1180 } else if (isTextFieldColumn()) {
1181 // calculate top label width
1182 columnWidth = myTopLabel->getFont()->getTextWidth(myTopLabel->getText().text(), myTopLabel->getText().length() + EXTRAMARGIN);
1183 // iterate over all textFields and check widths
1184 for (const auto& row : myTable->myRows) {
1185 // get text field
1186 const auto textField = row->getCells().at(myIndex)->getTextField();
1187 // get textField width
1188 const auto textFieldWidth = textField->getFont()->getTextWidth(textField->getText().text(), textField->getText().length() + EXTRAMARGIN);
1189 // compare widths
1190 if (textFieldWidth > columnWidth) {
1191 columnWidth = textFieldWidth;
1192 }
1193 }
1194 // calculate bot label width
1195 const auto botLabelWidth = myBotLabel->getFont()->getTextWidth(myBotLabel->getText().text(), myBotLabel->getText().length() + EXTRAMARGIN);
1196 if (botLabelWidth > columnWidth) {
1197 columnWidth = botLabelWidth;
1198 }
1199 } else {
1200 // is an index column, then return icon size
1201 columnWidth = GUIDesignHeight;
1202 }
1203 return columnWidth;
1204}
1205
1206
1207void
1209 // only adjust for textField columns
1210 if (isTextFieldColumn()) {
1211 for (const auto& row : myTable->myRows) {
1212 row->getCells().at(myIndex)->getTextField()->setWidth(colWidth);
1213 }
1214 }
1215 // adjust labels and vertical frames
1216 myVerticalFrame->setWidth(colWidth);
1217 myTopLabel->setWidth(colWidth);
1218 myVerticalCellFrame->setWidth(colWidth);
1219 myBotLabel->setWidth(colWidth);
1220}
1221
1222
1223bool
1225 return ((myType == 'u') || (myType == 'f') || (myType == 'p') || (myType == 'm') || (myType == '-'));
1226}
1227
1228
1230 myIndex(0),
1231 myType('-') {}
1232
1233// ---------------------------------------------------------------------------
1234// GNETLSTable::Row - methods
1235// ---------------------------------------------------------------------------
1236
1238 myTable(table) {
1239 const auto staticTooltipMenu = table->getTLSPhasesParent()->getTLSEditorParent()->getViewNet()->getViewParent()->getGNEAppWindows()->getStaticTooltipMenu();
1240 // build textFields
1241 for (int columnIndex = 0; columnIndex < (FXint)table->myColumns.size(); columnIndex++) {
1242 // get number of cells
1243 const int numCells = (int)myCells.size();
1244 // continue depending of type
1245 switch (table->myColumns.at(columnIndex)->getType()) {
1246 case ('s'): {
1247 // create labels for index
1248 auto indexLabel = new FXLabel(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1249 toString(myTable->myRows.size()).c_str(), nullptr, GUIDesignLabelThickedFixed(30));
1250 auto indexLabelBold = new FXLabel(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1251 toString(myTable->myRows.size()).c_str(), nullptr, GUIDesignLabelThickedFixed(30));
1252 // set fonts
1253 indexLabel->setFont(myTable->myIndexFont);
1254 indexLabelBold->setFont(myTable->myIndexSelectedFont);
1255 myCells.push_back(new Cell(table, indexLabel, indexLabelBold, columnIndex, numCells));
1256 break;
1257 }
1258 case ('u'):
1259 case ('f'):
1260 case ('m'):
1261 case ('-'): {
1262 // create textField for values
1263 auto textField = new MFXTextFieldIcon(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1264 staticTooltipMenu, GUIIcon::EMPTY, table,
1266 myCells.push_back(new Cell(table, textField, columnIndex, numCells));
1267 break;
1268 }
1269 case ('p'): {
1270 // create text field for program (state)
1271 auto textField = new MFXTextFieldIcon(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1272 staticTooltipMenu, GUIIcon::EMPTY, table,
1274 // set special font
1275 textField->setFont(myTable->myProgramFont);
1276 myCells.push_back(new Cell(table, textField, columnIndex, numCells));
1277 break;
1278 }
1279 case ('i'): {
1280 // create popup for adding new phases
1281 myCells.push_back(new Cell(table, columnIndex, numCells));
1282 break;
1283 }
1284 case ('d'): {
1285 // create button for delete phase
1286 auto button = new MFXButtonTooltip(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1287 staticTooltipMenu, (std::string("\t") + TL("Delete phase") + std::string("\t") + TL("Delete this phase.")).c_str(),
1289 myCells.push_back(new Cell(table, button, columnIndex, numCells));
1290 break;
1291 }
1292 case ('t'): {
1293 // create button for move up phase
1294 auto button = new MFXButtonTooltip(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1295 staticTooltipMenu, (std::string("\t") + TL("Move phase up") + std::string("\t") + TL("Move this phase up.")).c_str(),
1297 myCells.push_back(new Cell(table, button, columnIndex, numCells));
1298 break;
1299 }
1300 case ('b'): {
1301 // create button for move down phase
1302 auto button = new MFXButtonTooltip(table->myColumns.at(columnIndex)->getVerticalCellFrame(),
1303 staticTooltipMenu, (std::string("\t") + TL("Move phase down") + std::string("\t") + TL("Move this phase down.")).c_str(),
1305 myCells.push_back(new Cell(table, button, columnIndex, numCells));
1306 break;
1307 }
1308 default:
1309 throw ProcessError("Invalid Cell type");
1310 }
1311 }
1312}
1313
1314
1316 // delete all cells
1317 for (const auto& cell : myCells) {
1318 delete cell;
1319 }
1320}
1321
1322
1323std::string
1325 if (myCells.at(index)->getTextField()) {
1326 return myCells.at(index)->getTextField()->getText().text();
1327 } else {
1328 throw ProcessError("Cell doesn't have a textField");
1329 }
1330}
1331
1332
1333void
1334GNETLSTable::Row::setText(int index, const std::string& text) const {
1335 // set text
1336 myCells.at(index)->getTextField()->setText(text.c_str());
1337}
1338
1339
1340const std::vector<GNETLSTable::Cell*>&
1342 return myCells;
1343}
1344
1345
1346void
1348 // search move up button and disable it
1349 for (const auto& cell : myCells) {
1350 if ((cell->getType() == 'd') || (cell->getType() == 'b') || (cell->getType() == 't')) {
1351 cell->disableButton();
1352 }
1353 }
1354}
1355
1356
1358
1359/****************************************************************************/
#define EXTRAMARGIN
FXDEFMAP(GNETLSTable) GNETLSTableMap[]
#define DEFAULTWIDTH
@ MID_GNE_TLSTABLE_ADDPHASE
TLSTable button for add phase.
@ MID_GNE_TLSTABLE_COPYPHASE
TLSTable button for copy phase.
@ MID_GNE_TLSTABLE_ADDPHASEALLGREENPRIORITY
TLSTable button for add phase green priority.
@ MID_MBTTIP_SELECTED
@ MID_GNE_TLSTABLE_ADDPHASEALLYELLOW
TLSTable button for add phase yelllow.
@ MID_GNE_TLSTABLE_TEXTFIELD
TLSTable textField.
@ MID_GNE_TLSTABLE_ADDPHASEALLRED
TLSTable button for add phase red.
@ MID_GNE_TLSTABLE_MOVEDOWNPHASE
TLSTable button for move down phase.
@ MID_MBTTIP_FOCUS
callback for MFXMenuButtonTooltip
@ MID_GNE_TLSTABLE_ADDPHASEALLGREEN
TLSTable button for add phase green.
@ MID_GNE_TLSTABLE_REMOVEPHASE
TLSTable button for remove phase.
@ MID_GNE_TLSTABLE_MOVEUPPHASE
TLSTable button for move up phase.
#define GUIDesignTextColorRed
red color (for invalid text)
Definition GUIDesigns.h:44
#define GUIDesignLabelFixed(width)
label, icon before text, text centered and custom width
Definition GUIDesigns.h:248
#define GUIDesignButtonIcon
button only with icon
Definition GUIDesigns.h:109
#define GUIDesignTextFieldTLSTable
text field with min width (used in TLS table)
Definition GUIDesigns.h:86
#define GUIDesignAuxiliarFrameFixedWidth(width)
design for auxiliar (Without borders) frame with fixed width and extended height
Definition GUIDesigns.h:415
#define GUIDesignTLSTableCheckableButtonIcon
checkable button only with icon used in TLSTable
Definition GUIDesigns.h:127
#define GUIDesignTextColorBlack
black color (for correct text)
Definition GUIDesigns.h:38
#define GUIDesignLabelThickedFixed(width)
label thicked, icon before text, text centered and custom width
Definition GUIDesigns.h:254
@ TLSPHASEALLGREEN
@ TLSPHASEALLGREENPRIORITY
@ TLSPHASECOPY
@ TLSPHASEDEFAULT
@ TLSPHASEALLYELLOW
@ TLSPHASEALLRED
#define TL(string)
Definition MsgHandler.h:304
int GUIDesignHeight
the default height for GUI elements
Definition StdDefs.cpp:40
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
int getScrollBarWidth() const
get scrollBar width (zero if is hidden)
Definition GNEFrame.cpp:176
GNEViewNet * getViewNet() const
get view net
Definition GNEFrame.cpp:152
void movePhaseDown(const int row)
move phase down
bool changePhaseValue(const int col, const int row, const std::string &value)
change phase value (state, name, next, etc.)
void movePhaseUp(const int row)
move phase up
void updateTLSColoring()
update TLS coloring
void removePhase(const int row)
delete phase
void duplicatePhase(const int row)
duplicate phase
void addPhase(const int row, const char c=' ')
add phase
GNETLSEditorFrame * getTLSEditorParent() const
get TLSEditor Parent
FOX needs this.
void showIndexLabelNormal()
show label index normal
MFXButtonTooltip * getDuplicatePhaseButton()
get duplicate phase button
MFXButtonTooltip * myAddAllGreenPriorityButton
add all green priority phase button
MFXButtonTooltip * myAddAllRedButton
add all red phase button
void enable()
Enable cell.
void showIndexLabelBold()
show label index bold
MFXButtonTooltip * getAddPhaseButton()
get add phase button
int getCol() const
column index
void setFocus()
set focus in the current cell
void setTooltip(const std::string &toolTip)
set tooltip
bool hasFocus() const
check if current cell has focus
Cell()
default constructor
GNETLSTable * myTLSTable
pointer to TLSTable parent
FXPopup * myMenuButtonPopup
popup for buttons
MFXButtonTooltip * getAddAllGreenPriorityPhaseButton()
get add all green priority phase button
MFXButtonTooltip * getAddAllYellowPhaseButton()
get add all yellow phase button
MFXTextFieldIcon * getTextField() const
get textField
int getRow() const
row index
void disableButton()
disable button (used for delete, move up and move down)
MFXMenuButtonTooltip * myAddButton
menu button tooltip
void hideMenuButtonPopup()
hide menuButton popup
FXLabel * getIndexLabel() const
get index label
double getDoubleValue() const
get double value (only for types 'u' and 'd')
MFXButtonTooltip * getButton()
get remove, move up or move down button
MFXMenuButtonTooltip * getAddButton() const
get add button
MFXButtonTooltip * myAddAllYellowButton
add all yellow phase button
void disable()
Disable cell.
MFXButtonTooltip * getAddAllGreenPhaseButton()
get add all green phase button
char getType() const
get column type
MFXButtonTooltip * getAddAllRedPhaseButton()
get add all red phase button
MFXButtonTooltip * myDuplicatePhaseButton
duplicate phase button
MFXButtonTooltip * myAddPhaseButton
add phase button
MFXButtonTooltip * myAddAllGreenButton
add all green phase button
int getColumnMinimumWidth()
get column minimum width
const char myType
column type
FXVerticalFrame * myVerticalFrame
vertical frame
FXLabel * myBotLabel
column bot label
Column()
default constructor
FXVerticalFrame * getVerticalCellFrame() const
get vertical cell frame
FXVerticalFrame * myVerticalCellFrame
vertical frame
void setColumnLabelTop(const std::string &text, const std::string &tooltip)
set column label top
bool isTextFieldColumn() const
check if current type correspond to a textField
char getType() const
get column type
FXString getColumnLabelTop() const
get column label top
void setColumnLabelBot(const std::string &text)
set column label boit
MFXLabelTooltip * myTopLabel
column top tooltip label
void setColumnWidth(const int colWidth)
set colum width
void setText(int index, const std::string &text) const
set text
Row()
default constructor
GNETLSTable * myTable
poiner to table parent
std::vector< Cell * > myCells
list wtih cells
void disableButtons()
disable row buttons
const std::vector< Cell * > & getCells() const
get cells
std::string getText(int index) const
get text
GNETLSEditorFrame::TLSPhases * myTLSPhasesParent
@frame pointer to TLSEditorFrame phases parent
int getNumRows() const
Get number of rows.
int myCurrentSelectedRow
current selected row
long onCmdDuplicatePhase(FXObject *, FXSelector, void *)
called when a duplicate phase button is pressed
long onCmdEditRow(FXObject *, FXSelector, void *)
called when a row is modified
FXFont * myIndexSelectedFont
font for index selected
long onCmdAddPhaseAllRed(FXObject *, FXSelector, void *)
called when an add all green red phase button is pressed
long onCmdAddPhaseAllGreenPriority(FXObject *, FXSelector, void *)
called when an add all green red phase button is pressed
long testTable(const InternalTestStep::TLSTableTest *tableTest)
test table (using internal tests)
long onCmdAddPhase(FXObject *, FXSelector, void *)
called when an add phase button is pressed
void updateIndexLabel()
update index labels
long onFocusRow(FXObject *, FXSelector, void *)
called when a row is focused
void setColumnLabelBot(const int column, const std::string &text)
Change column bottom text.
void clearTable()
clear table
void selectRow(const int rowIndex)
Select a row.
long onCmdMoveUpPhase(FXObject *, FXSelector, void *)
called when a move up phase button is pressed
~GNETLSTable()
destructor (Called automatically)
int getCurrentSelectedRow() const
Get current selected row.
long onCmdAddPhasePressed(FXObject *, FXSelector, void *)
called when add phase button is selected
FXFont * myIndexFont
font for index
void enable()
Enable table.
long onCmdAddPhaseAllYellow(FXObject *, FXSelector, void *)
called when an add all green red phase button is pressed
std::string getItemText(const int row, const int column) const
Return cell text.
long onCmdKeyPress(FXObject *, FXSelector, void *)
called when a key is pressed
long onCmdAddPhaseAllGreen(FXObject *, FXSelector, void *)
called when an add all green red phase button is pressed
bool moveFocus()
move focus to current row
void setColumnLabelTop(const int column, const std::string &text, const std::string &tooltip="")
Change column header text.
void setItemText(FXint row, FXint column, const std::string &text)
Modify cell text.
std::vector< Row * > myRows
rows
long onCmdRemovePhase(FXObject *, FXSelector, void *)
called when a remove phase button is pressed
void updateAccumulatedDuration()
update accumulated duration();
void setTableSize(const std::string &columnsType, const int numberRow)
Set the table size to nr rows and nc columns; all existing items will be removed. Format: s -> select...
FXFont * myProgramFont
font for the phase table
void disable()
Disable table.
long onCmdMoveDownPhase(FXObject *, FXSelector, void *)
called when a move up phase button is pressed
void recalcTableWidth()
recalc width (call when all labels and contents are fill)
GNETLSEditorFrame::TLSPhases * getTLSPhasesParent() const
@frame get pointer to TLSEditorFrame phases parent
std::vector< Column * > myColumns
columns
GNEViewParent * getViewParent() const
get the net object
GNEApplicationWindow * getGNEAppWindows() const
get GNE Application Windows
int getFrameAreaWidth() const
get frame area width
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
MFXStaticToolTip * getStaticTooltipMenu() const
get static toolTip for menus
struct used for test TLS Tables
const FXSelector sel
selector
virtual void create()
Create server-side resources.
void setText(const FXString &text, FXbool notify=FALSE)
Change the text and move cursor to end.