Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/foxtools/MFXComboBoxIcon.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2006-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 MFXComboBoxIcon.cpp
15
/// @author Jakob Erdmann
16
/// @author Pablo Alvarez Lopez
17
/// @date 2018-12-19
18
///
19
//
20
/****************************************************************************/
21
22
#include <utils/common/MsgHandler.h>
23
#include <utils/gui/div/GUIDesigns.h>
24
#include <utils/gui/images/GUIIconSubSys.h>
25
#include <utils/gui/windows/GUIAppEnum.h>
26
27
#include "MFXComboBoxIcon.h"
28
#include "MFXListIcon.h"
29
#include "MFXListIconItem.h"
30
#include "MFXTextFieldSearch.h"
31
32
// =========================================================================
33
// defines
34
// =========================================================================
35
36
#define ICON_SPACING 4 // Spacing between icon and label (2 + 2)
37
#define ICON_SIZE 16
38
39
// ===========================================================================
40
// FOX callback mapping
41
// ===========================================================================
42
43
FXDEFMAP(MFXComboBoxIcon) MFXComboBoxIconMap[] = {
44
FXMAPFUNC(SEL_FOCUS_UP, 0, MFXComboBoxIcon::onFocusUp),
45
FXMAPFUNC(SEL_FOCUS_DOWN, 0, MFXComboBoxIcon::onFocusDown),
46
FXMAPFUNC(SEL_FOCUS_SELF, 0, MFXComboBoxIcon::onFocusSelf),
47
FXMAPFUNC(SEL_UPDATE, MFXComboBoxIcon::ID_TEXT, MFXComboBoxIcon::onUpdFmText),
48
FXMAPFUNC(SEL_CLICKED, MFXComboBoxIcon::ID_LIST, MFXComboBoxIcon::onListClicked),
49
FXMAPFUNC(SEL_COMMAND, MFXComboBoxIcon::ID_LIST, MFXComboBoxIcon::onListClicked),
50
FXMAPFUNC(SEL_LEFTBUTTONPRESS, MFXComboBoxIcon::ID_TEXT, MFXComboBoxIcon::onTextButton),
51
FXMAPFUNC(SEL_MOUSEWHEEL, MFXComboBoxIcon::ID_TEXT, MFXComboBoxIcon::onMouseWheel),
52
FXMAPFUNC(SEL_CHANGED, MFXComboBoxIcon::ID_TEXT, MFXComboBoxIcon::onTextChanged),
53
FXMAPFUNC(SEL_COMMAND, MFXComboBoxIcon::ID_TEXT, MFXComboBoxIcon::onTextCommand),
54
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETVALUE, MFXComboBoxIcon::onFwdToText),
55
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETINTVALUE, MFXComboBoxIcon::onFwdToText),
56
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETREALVALUE, MFXComboBoxIcon::onFwdToText),
57
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETSTRINGVALUE, MFXComboBoxIcon::onFwdToText),
58
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_GETINTVALUE, MFXComboBoxIcon::onFwdToText),
59
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_GETREALVALUE, MFXComboBoxIcon::onFwdToText),
60
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_GETSTRINGVALUE, MFXComboBoxIcon::onFwdToText),
61
FXMAPFUNC(SEL_COMMAND, MID_MTEXTFIELDSEARCH_UPDATED, MFXComboBoxIcon::onCmdFilter),
62
};
63
64
// Object implementation
65
FXIMPLEMENT(MFXComboBoxIcon, FXPacker, MFXComboBoxIconMap, ARRAYNUMBER(MFXComboBoxIconMap))
66
67
// ===========================================================================
68
// member method definitions
69
// ===========================================================================
70
71
MFXComboBoxIcon::MFXComboBoxIcon(FXComposite* p, MFXStaticToolTip* staticToolTip, const bool canSearch, const int visibleItems,
72
FXObject* tgt, FXSelector sel, FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb):
73
FXPacker(p, opts, x, y, w, h, 0, 0, 0, 0, 0, 0) {
74
flags |= FLAG_ENABLED;
75
target = tgt;
76
message = sel;
77
// create text field
78
myTextFieldIcon = new MFXTextFieldIcon(this, staticToolTip, GUIIcon::EMPTY, this, MFXComboBoxIcon::ID_TEXT, 0, 0, 0, 0, 0, pl, pr, pt, pb);
79
if (options & COMBOBOX_STATIC) {
80
myTextFieldIcon->setEditable(FALSE);
81
}
82
// create pane for list
83
myPane = new FXPopup(this, FRAME_LINE);
84
// check if create search button
85
if (canSearch) {
86
myTextFieldSearch = new MFXTextFieldSearch(myPane, staticToolTip, this, ID_SEARCH, FRAME_THICK | LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT, 0, 0, 0, 0, 2, 2, 2, 2);
87
// create label for empty icon
88
myNoItemsLabel = new FXLabel(myPane, TL("No matches found"), nullptr, FRAME_THICK | LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT, 0, 0, 0, 0, 2, 2, 2, 2);
89
myNoItemsLabel->setTextColor(GUIDesignTextColorRed);
90
myNoItemsLabel->hide();
91
}
92
// create list icon
93
myList = new MFXListIcon(myPane, this, MFXComboBoxIcon::ID_LIST, LIST_BROWSESELECT | LIST_AUTOSELECT | LAYOUT_FILL_X | LAYOUT_FILL_Y | SCROLLERS_TRACK | HSCROLLER_NEVER);
94
if (options & COMBOBOX_STATIC) {
95
myList->setScrollStyle(SCROLLERS_TRACK | HSCROLLING_OFF);
96
}
97
myList->setNumVisible(visibleItems);
98
// create button
99
myButton = new FXMenuButton(this, FXString::null, NULL, myPane, FRAME_RAISED | FRAME_THICK | MENUBUTTON_DOWN | MENUBUTTON_ATTACH_RIGHT, 0, 0, 0, 0, 0, 0, 0, 0);
100
myButton->setXOffset(border);
101
myButton->setYOffset(border);
102
flags &= ~(FXuint)FLAG_UPDATE; // Never GUI update
103
104
}
105
106
107
MFXComboBoxIcon::~MFXComboBoxIcon() {
108
delete myPane;
109
myPane = (FXPopup*) - 1L;
110
myTextFieldIcon = (MFXTextFieldIcon*) - 1L;
111
myButton = (FXMenuButton*) - 1L;
112
if (myTextFieldSearch) {
113
myTextFieldSearch = (MFXTextFieldSearch*) - 1L;
114
myNoItemsLabel = (FXLabel*) - 1L;
115
}
116
myList = (MFXListIcon*) - 1L;
117
}
118
119
120
void
121
MFXComboBoxIcon::create() {
122
FXPacker::create();
123
myPane->create();
124
}
125
126
127
void
128
MFXComboBoxIcon::detach() {
129
FXPacker::detach();
130
myPane->detach();
131
}
132
133
134
void
135
MFXComboBoxIcon::destroy() {
136
myPane->destroy();
137
FXPacker::destroy();
138
}
139
140
141
void
142
MFXComboBoxIcon::enable() {
143
if (!isEnabled()) {
144
FXPacker::enable();
145
myTextFieldIcon->enable();
146
myButton->enable();
147
}
148
}
149
150
151
void
152
MFXComboBoxIcon::disable() {
153
if (isEnabled()) {
154
FXPacker::disable();
155
myTextFieldIcon->disable();
156
myButton->disable();
157
}
158
}
159
160
161
FXint
162
MFXComboBoxIcon::getDefaultWidth() {
163
FXint ww = myTextFieldIcon->getDefaultWidth() + myButton->getDefaultWidth() + (border << 1);
164
FXint pw = myPane->getDefaultWidth();
165
return FXMAX(ww, pw);
166
}
167
168
169
FXint
170
MFXComboBoxIcon::getDefaultHeight() {
171
FXint th, bh;
172
th = myTextFieldIcon->getDefaultHeight();
173
bh = myButton->getDefaultHeight();
174
return FXMAX(th, bh) + (border << 1);
175
}
176
177
178
void
179
MFXComboBoxIcon::layout() {
180
const FXint itemHeight = height - (border << 1);
181
const FXint buttonWidth = myButton->getDefaultWidth();
182
const FXint textWidth = width - buttonWidth - (border << 1);
183
myTextFieldIcon->position(border, border, textWidth, itemHeight);
184
myButton->position(border + textWidth, border, buttonWidth, itemHeight);
185
if (myTextFieldSearch) {
186
myTextFieldSearch->resize(width, height);
187
myNoItemsLabel->resize(width, height);
188
}
189
myPane->resize(width, myPane->getDefaultHeight());
190
flags &= ~(FXuint)FLAG_DIRTY;
191
}
192
193
194
FXString
195
MFXComboBoxIcon::getText() const {
196
return myTextFieldIcon->getText();
197
}
198
199
200
FXint
201
MFXComboBoxIcon::getNumItems() const {
202
return myList->getNumItems();
203
}
204
205
206
void
207
MFXComboBoxIcon::setNumVisible(FXint nvis) {
208
myList->setNumVisible(nvis);
209
}
210
211
212
void
213
MFXComboBoxIcon::setText(const FXString& text, FXbool notify) {
214
myTextFieldIcon->setText(text, notify);
215
}
216
217
218
FXbool
219
MFXComboBoxIcon::isItemCurrent(FXint index) const {
220
return myList->isItemCurrent(index);
221
}
222
223
224
long
225
MFXComboBoxIcon::setCurrentItem(const FXint index, FXbool notify) {
226
if (index >= 0 && index <= myList->getNumItems()) {
227
// get item
228
MFXListIconItem* item = myList->getItem(index);
229
// set it as current item and make it visible
230
myList->setCurrentItem(item);
231
myList->makeItemVisible(index);
232
// update both text fields
233
myTextFieldIcon->setText(item->getText());
234
myTextFieldIcon->setIcon(item->getIcon());
235
myTextFieldIcon->setBackColor(item->getBackGroundColor());
236
// check if notify
237
if (notify && target) {
238
return target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)item);
239
}
240
} else {
241
fxerror("%s::setItem: index out of range.\n", getClassName());
242
}
243
return 0;
244
}
245
246
247
long
248
MFXComboBoxIcon::setCurrentItem(const FXString& text, FXbool notify) {
249
// check if item exist
250
for (int i = 0; i < myList->getNumItems(); i++) {
251
const auto itemText = myList->tolowerString(myList->getItem(i)->getText());
252
if (myList->tolowerString(text) == itemText) {
253
// use "set curent item" function
254
return setCurrentItem(i, notify);
255
}
256
}
257
return 0;
258
}
259
260
261
FXint
262
MFXComboBoxIcon::getCurrentItem() const {
263
return myList->getCurrentItemIndex();
264
}
265
266
267
FXint
268
MFXComboBoxIcon::updateIconItem(FXint index, const FXString& text, FXIcon* icon, FXColor bgColor, void* ptr) {
269
if (index < 0 || myList->getNumItems() <= index) {
270
fxerror("%s::setItem: index out of range.\n", getClassName());
271
}
272
myList->editItem(index, text, NULL, ptr);
273
if (isItemCurrent(index)) {
274
myTextFieldIcon->setText(text);
275
myTextFieldIcon->setBackColor(bgColor);
276
myTextFieldIcon->setIcon(icon);
277
}
278
recalc();
279
return index;
280
}
281
282
283
FXint
284
MFXComboBoxIcon::insertIconItem(FXint index, const FXString& text, FXIcon* icon, FXColor bgColor, void* ptr) {
285
index = myList->insertItem(index, new MFXListIconItem(text, icon, bgColor, ptr));
286
if (isItemCurrent(index)) {
287
myTextFieldIcon->setText(text);
288
myTextFieldIcon->setBackColor(bgColor);
289
myTextFieldIcon->setIcon(icon);
290
}
291
recalc();
292
return index;
293
}
294
295
296
FXint
297
MFXComboBoxIcon::appendIconItem(const FXString& text, FXIcon* icon, FXColor bgColor, void* ptr) {
298
FXint index = myList->appendItem(new MFXListIconItem(text, icon, bgColor, ptr));
299
if (isItemCurrent(getNumItems() - 1)) {
300
myTextFieldIcon->setText(text);
301
myTextFieldIcon->setBackColor(bgColor);
302
myTextFieldIcon->setIcon(icon);
303
}
304
recalc();
305
return index;
306
}
307
308
309
void
310
MFXComboBoxIcon::removeItem(FXint index) {
311
const auto isCurrent = myList->isItemCurrent(index);
312
if (isCurrent == TRUE) {
313
if ((index > 0) && (index < (int)myList->getNumItems())) {
314
setCurrentItem(index - 1);
315
} else if (myList->getNumItems() > 0) {
316
setCurrentItem(0);
317
}
318
}
319
myList->removeItem(index);
320
recalc();
321
}
322
323
324
void
325
MFXComboBoxIcon::clearItems() {
326
myTextFieldIcon->setText("");
327
myList->clearItems();
328
recalc();
329
}
330
331
332
FXint
333
MFXComboBoxIcon::findItem(const FXString& text) const {
334
return myList->findItem(text);
335
}
336
337
338
std::string
339
MFXComboBoxIcon::getItemText(FXint index) const {
340
return myList->getItem(index)->getText().text();
341
}
342
343
344
void
345
MFXComboBoxIcon::setBackColor(FXColor clr) {
346
myTextFieldIcon->setBackColor(clr);
347
myList->setBackColor(clr);
348
}
349
350
351
void
352
MFXComboBoxIcon::setTextColor(FXColor clr) {
353
myTextFieldIcon->setTextColor(clr);
354
myList->setTextColor(clr);
355
}
356
357
358
FXColor
359
MFXComboBoxIcon::getTextColor() const {
360
return myTextFieldIcon->getTextColor();
361
}
362
363
364
void
365
MFXComboBoxIcon::setTipText(const FXString& txt) {
366
myTextFieldIcon->setTipText(txt);
367
}
368
369
370
const FXString&
371
MFXComboBoxIcon::getTipText() const {
372
return myTextFieldIcon->getTipText();
373
}
374
375
376
long
377
MFXComboBoxIcon::onUpdFmText(FXObject*, FXSelector, void*) {
378
return (target && !myPane->shown()) ? target->tryHandle(this, FXSEL(SEL_UPDATE, message), NULL) : 0;
379
}
380
381
382
long
383
MFXComboBoxIcon::onCmdFilter(FXObject*, FXSelector, void* ptr) {
384
myList->setFilter(myTextFieldSearch->getText(), myNoItemsLabel);
385
myPane->resize(width, myPane->getDefaultHeight());
386
myPane->recalc();
387
myPane->onPaint(0, 0, ptr);
388
return 1;
389
}
390
391
392
long
393
MFXComboBoxIcon::onFwdToText(FXObject* sender, FXSelector sel, void* ptr) {
394
return myTextFieldIcon->handle(sender, sel, ptr);
395
}
396
397
398
long
399
MFXComboBoxIcon::onListClicked(FXObject*, FXSelector sel, void* ptr) {
400
// hide pane
401
myButton->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
402
if (FXSELTYPE(sel) == SEL_COMMAND) {
403
// cast MFXListIconItem
404
const MFXListIconItem* item = (MFXListIconItem*)ptr;
405
// set icon and background color
406
myTextFieldIcon->setText(item->getText());
407
myTextFieldIcon->setIcon(item->getIcon());
408
myTextFieldIcon->setBackColor(item->getBackGroundColor());
409
// Select if editable
410
if (!(options & COMBOBOX_STATIC)) {
411
myTextFieldIcon->selectAll();
412
}
413
if (target) {
414
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)getText().text());
415
}
416
}
417
return 1;
418
}
419
420
421
long
422
MFXComboBoxIcon::onTextButton(FXObject*, FXSelector, void*) {
423
if (options & COMBOBOX_STATIC) {
424
// Post the myList
425
myButton->handle(this, FXSEL(SEL_COMMAND, ID_POST), NULL);
426
return 1;
427
}
428
return 0;
429
}
430
431
432
long
433
MFXComboBoxIcon::onTextChanged(FXObject*, FXSelector, void* ptr) {
434
return target ? target->tryHandle(this, FXSEL(SEL_CHANGED, message), ptr) : 0;
435
}
436
437
438
long
439
MFXComboBoxIcon::onTextCommand(FXObject*, FXSelector, void* ptr) {
440
// reset background colors
441
myTextFieldIcon->setBackColor(GUIDesignBackgroundColorWhite);
442
// check if item exist
443
for (int i = 0; i < myList->getNumItems(); i++) {
444
const auto itemText = myList->tolowerString(myList->getItem(i)->getText());
445
if (myList->tolowerString(myTextFieldIcon->getText()) == itemText) {
446
// use "set curent item" function
447
return setCurrentItem(i, TRUE);
448
}
449
}
450
// no item found, then reset icon label
451
myTextFieldIcon->setIcon(GUIIconSubSys::getIcon(GUIIcon::CANCEL));
452
return target ? target->tryHandle(this, FXSEL(SEL_COMMAND, message), ptr) : 0;
453
}
454
455
456
long
457
MFXComboBoxIcon::onFocusSelf(FXObject* sender, FXSelector, void* ptr) {
458
return myTextFieldIcon->handle(sender, FXSEL(SEL_FOCUS_SELF, 0), ptr);
459
}
460
461
462
long
463
MFXComboBoxIcon::onFocusUp(FXObject*, FXSelector, void*) {
464
if (isEnabled()) {
465
FXint index = getCurrentItem();
466
if (index < 0) {
467
index = getNumItems() - 1;
468
} else if (0 < index) {
469
index--;
470
}
471
if (0 <= index && index < getNumItems()) {
472
setCurrentItem(index, TRUE);
473
}
474
return 1;
475
}
476
return 0;
477
}
478
479
480
long
481
MFXComboBoxIcon::onFocusDown(FXObject*, FXSelector, void*) {
482
if (isEnabled()) {
483
FXint index = getCurrentItem();
484
if (index < 0) {
485
index = 0;
486
} else if (index < getNumItems() - 1) {
487
index++;
488
}
489
if (0 <= index && index < getNumItems()) {
490
setCurrentItem(index, TRUE);
491
}
492
return 1;
493
}
494
return 0;
495
}
496
497
498
long MFXComboBoxIcon::onMouseWheel(FXObject*, FXSelector, void* ptr) {
499
FXEvent* event = (FXEvent*)ptr;
500
if (isEnabled()) {
501
FXint index = getCurrentItem();
502
if (event->code < 0) {
503
if (index < 0) {
504
index = 0;
505
} else if (index < getNumItems() - 1) {
506
index++;
507
}
508
} else if (event->code > 0) {
509
if (index < 0) {
510
index = getNumItems() - 1;
511
} else if (0 < index) {
512
index--;
513
}
514
}
515
if (0 <= index && index < getNumItems()) {
516
setCurrentItem(index, TRUE);
517
}
518
return 1;
519
}
520
return 0;
521
}
522
523
524
MFXComboBoxIcon::MFXComboBoxIcon() {}
525
526