Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/foxtools/MFXMenuCheckIcon.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2004-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 MFXMenuCheckIcon.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Jan 2021
17
///
18
//
19
/****************************************************************************/
20
21
#include <fxkeys.h>
22
23
#include "MFXMenuCheckIcon.h"
24
25
26
#define LEADSPACE 22
27
#define TRAILSPACE 16
28
29
// ===========================================================================
30
// FOX callback mapping
31
// ===========================================================================
32
33
FXDEFMAP(MFXMenuCheckIcon) MFXMenuCheckIconMap[] = {
34
FXMAPFUNC(SEL_PAINT, 0, MFXMenuCheckIcon::onPaint),
35
FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, MFXMenuCheckIcon::onButtonPress),
36
FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, MFXMenuCheckIcon::onButtonRelease),
37
FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, MFXMenuCheckIcon::onButtonPress),
38
FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, MFXMenuCheckIcon::onButtonRelease),
39
FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, MFXMenuCheckIcon::onButtonPress),
40
FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, MFXMenuCheckIcon::onButtonRelease),
41
FXMAPFUNC(SEL_KEYPRESS, 0, MFXMenuCheckIcon::onKeyPress),
42
FXMAPFUNC(SEL_KEYRELEASE, 0, MFXMenuCheckIcon::onKeyRelease),
43
FXMAPFUNC(SEL_KEYPRESS, FXWindow::ID_HOTKEY, MFXMenuCheckIcon::onHotKeyPress),
44
FXMAPFUNC(SEL_KEYRELEASE, FXWindow::ID_HOTKEY, MFXMenuCheckIcon::onHotKeyRelease),
45
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_CHECK, MFXMenuCheckIcon::onCheck),
46
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_UNCHECK, MFXMenuCheckIcon::onUncheck),
47
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_UNKNOWN, MFXMenuCheckIcon::onUnknown),
48
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETVALUE, MFXMenuCheckIcon::onCmdSetValue),
49
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETINTVALUE, MFXMenuCheckIcon::onCmdSetIntValue),
50
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_GETINTVALUE, MFXMenuCheckIcon::onCmdGetIntValue),
51
FXMAPFUNC(SEL_COMMAND, FXWindow::ID_ACCEL, MFXMenuCheckIcon::onCmdAccel),
52
};
53
54
// Object implementation
55
FXIMPLEMENT(MFXMenuCheckIcon, FXMenuCommand, MFXMenuCheckIconMap, ARRAYNUMBER(MFXMenuCheckIconMap))
56
57
// ===========================================================================
58
// member method definitions
59
// ===========================================================================
60
61
MFXMenuCheckIcon::MFXMenuCheckIcon(FXComposite* p, const std::string& text, const std::string& shortcut, const std::string& info, const FXIcon* icon, FXObject* tgt, FXSelector sel, FXuint opts) :
62
FXMenuCommand(p, (text + "\t" + shortcut + "\t" + info).c_str(), NULL, tgt, sel, opts),
63
myIcon(icon),
64
myCheck(FALSE),
65
myBoxColor(getApp()->getBackColor()) {
66
}
67
68
69
FXint
70
MFXMenuCheckIcon::getDefaultWidth() {
71
FXint tw, aw;
72
tw = aw = 0;
73
if (!label.empty()) {
74
tw = font->getTextWidth(label.text(), label.length());
75
}
76
if (!accel.empty()) {
77
aw = font->getTextWidth(accel.text(), accel.length());
78
}
79
if (aw && tw) {
80
aw += 5;
81
}
82
// return width depending of icon
83
if (myIcon) {
84
return LEADSPACE + (myIcon->getWidth() + 5) + tw + aw + TRAILSPACE;
85
} else {
86
return LEADSPACE + tw + aw + TRAILSPACE;
87
}
88
}
89
90
91
FXint
92
MFXMenuCheckIcon::getDefaultHeight() {
93
FXint th = 0;
94
if (!label.empty() || !accel.empty()) {
95
th = font->getFontHeight() + 5;
96
}
97
return FXMAX(th, 20);
98
}
99
100
101
void
102
MFXMenuCheckIcon::setCheck(FXbool s) {
103
if (myCheck != s) {
104
myCheck = s;
105
update();
106
}
107
}
108
109
110
void
111
MFXMenuCheckIcon::toggleCheck() {
112
if (myCheck == TRUE) {
113
setCheck(FALSE);
114
} else if (myCheck == FALSE) {
115
setCheck(TRUE);
116
} else {
117
setCheck(MAYBE);
118
}
119
}
120
121
122
FXbool
123
MFXMenuCheckIcon::getCheck() const {
124
return myCheck;
125
}
126
127
128
FXColor
129
MFXMenuCheckIcon::getBoxColor() const {
130
return myBoxColor;
131
}
132
133
134
long
135
MFXMenuCheckIcon::onCheck(FXObject*, FXSelector, void*) {
136
setCheck(TRUE);
137
return 1;
138
}
139
140
141
long
142
MFXMenuCheckIcon::onUncheck(FXObject*, FXSelector, void*) {
143
setCheck(FALSE);
144
return 1;
145
}
146
147
148
long
149
MFXMenuCheckIcon::onUnknown(FXObject*, FXSelector, void*) {
150
setCheck(MAYBE);
151
return 1;
152
}
153
154
155
long
156
MFXMenuCheckIcon::onCmdSetValue(FXObject*, FXSelector, void* ptr) {
157
setCheck((FXbool)(FXuval)ptr);
158
return 1;
159
}
160
161
162
long
163
MFXMenuCheckIcon::onCmdSetIntValue(FXObject*, FXSelector, void* ptr) {
164
setCheck((FXbool) * ((FXint*)ptr));
165
return 1;
166
}
167
168
169
long
170
MFXMenuCheckIcon::onCmdGetIntValue(FXObject*, FXSelector, void* ptr) {
171
*((FXint*)ptr) = getCheck();
172
return 1;
173
}
174
175
176
long
177
MFXMenuCheckIcon::onButtonPress(FXObject*, FXSelector, void*) {
178
if (!isEnabled()) {
179
return 0;
180
}
181
return 1;
182
}
183
184
185
long
186
MFXMenuCheckIcon::onButtonRelease(FXObject*, FXSelector, void*) {
187
FXbool active = isActive();
188
if (!isEnabled()) {
189
return 0;
190
}
191
// keep menu open
192
//getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
193
if (active) {
194
setCheck(!myCheck);
195
if (target) {
196
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
197
}
198
}
199
return 1;
200
}
201
202
203
long
204
MFXMenuCheckIcon::onKeyPress(FXObject*, FXSelector, void* ptr) {
205
FXEvent* event = (FXEvent*)ptr;
206
if (isEnabled() && !(flags & FLAG_PRESSED)) {
207
FXTRACE((200, "%s::onKeyPress %p keysym = 0x%04x state = %04x\n", getClassName(), (void*)this, event->code, event->state));
208
if (event->code == FX::KEY_space || event->code == FX::KEY_KP_Space || event->code == FX::KEY_Return || event->code == FX::KEY_KP_Enter) {
209
flags |= FLAG_PRESSED;
210
return 1;
211
}
212
}
213
return 0;
214
}
215
216
217
long
218
MFXMenuCheckIcon::onKeyRelease(FXObject*, FXSelector, void* ptr) {
219
FXEvent* event = (FXEvent*)ptr;
220
if (isEnabled() && (flags & FLAG_PRESSED)) {
221
FXTRACE((200, "%s::onKeyRelease %p keysym = 0x%04x state = %04x\n", getClassName(), (void*)this, event->code, event->state));
222
if (event->code == FX::KEY_space || event->code == FX::KEY_KP_Space || event->code == FX::KEY_Return || event->code == FX::KEY_KP_Enter) {
223
flags &= ~FLAG_PRESSED;
224
setCheck(!myCheck);
225
getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
226
if (target) {
227
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
228
}
229
return 1;
230
}
231
}
232
return 0;
233
}
234
235
236
long
237
MFXMenuCheckIcon::onHotKeyPress(FXObject*, FXSelector, void* ptr) {
238
FXTRACE((200, "%s::onHotKeyPress %p\n", getClassName(), (void*)this));
239
handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
240
if (isEnabled() && !(flags & FLAG_PRESSED)) {
241
flags |= FLAG_PRESSED;
242
}
243
return 1;
244
}
245
246
247
long
248
MFXMenuCheckIcon::onHotKeyRelease(FXObject*, FXSelector, void*) {
249
FXTRACE((200, "%s::onHotKeyRelease %p\n", getClassName(), (void*)this));
250
if (isEnabled() && (flags & FLAG_PRESSED)) {
251
flags &= ~FLAG_PRESSED;
252
setCheck(!myCheck);
253
getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
254
if (target) {
255
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
256
}
257
}
258
return 1;
259
}
260
261
262
long
263
MFXMenuCheckIcon::onCmdAccel(FXObject*, FXSelector, void*) {
264
if (isEnabled()) {
265
setCheck(!myCheck);
266
if (target) {
267
target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
268
}
269
return 1;
270
}
271
return 0;
272
}
273
274
275
long
276
MFXMenuCheckIcon::onPaint(FXObject*, FXSelector, void* ptr) {
277
FXEvent* ev = (FXEvent*)ptr;
278
FXDCWindow dc(this, ev);
279
FXint xx, yy;
280
// set xx depending of myIcon
281
if (myIcon) {
282
xx = LEADSPACE + myIcon->getWidth() + 5;
283
} else {
284
xx = LEADSPACE;
285
}
286
// begin draw
287
if (!isEnabled()) {
288
// Grayed out
289
dc.setForeground(backColor);
290
dc.fillRectangle(0, 0, width, height);
291
if (!label.empty()) {
292
yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
293
dc.setFont(font);
294
dc.setForeground(hiliteColor);
295
dc.drawText(xx + 1, yy + 1, label);
296
if (!accel.empty()) {
297
dc.drawText(width - TRAILSPACE - font->getTextWidth(accel) + 1, yy + 1, accel);
298
}
299
if (0 <= hotoff) {
300
dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff) + 1, yy + 2, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
301
}
302
dc.setForeground(shadowColor);
303
dc.drawText(xx, yy, label);
304
if (!accel.empty()) {
305
dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
306
}
307
if (0 <= hotoff) {
308
dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
309
}
310
}
311
} else if (isActive()) {
312
// Active
313
dc.setForeground(selbackColor);
314
dc.fillRectangle(0, 0, width, height);
315
if (!label.empty()) {
316
yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
317
dc.setFont(font);
318
dc.setForeground(isEnabled() ? seltextColor : shadowColor);
319
dc.drawText(xx, yy, label);
320
if (!accel.empty()) {
321
dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
322
}
323
if (0 <= hotoff) {
324
dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
325
}
326
}
327
} else {
328
// Normal
329
dc.setForeground(backColor);
330
dc.fillRectangle(0, 0, width, height);
331
if (!label.empty()) {
332
yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
333
dc.setFont(font);
334
dc.setForeground(textColor);
335
dc.drawText(xx, yy, label);
336
if (!accel.empty()) {
337
dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
338
}
339
if (0 <= hotoff) {
340
dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
341
}
342
}
343
}
344
// Draw the box
345
xx = 5;
346
yy = (height - 9) / 2;
347
if (!isEnabled()) {
348
dc.setForeground(backColor);
349
} else {
350
dc.setForeground(myBoxColor);
351
dc.fillRectangle(xx + 1, yy + 1, 8, 8);
352
dc.setForeground(shadowColor);
353
dc.drawRectangle(xx, yy, 9, 9);
354
}
355
// Draw the check (tick)
356
if (myCheck != FALSE) {
357
FXSegment seg[6];
358
seg[0].x1 = 2 + (FXshort)xx;
359
seg[0].y1 = 4 + (FXshort)yy;
360
seg[0].x2 = 4 + (FXshort)xx;
361
seg[0].y2 = 6 + (FXshort)yy;
362
seg[1].x1 = 2 + (FXshort)xx;
363
seg[1].y1 = 5 + (FXshort)yy;
364
seg[1].x2 = 4 + (FXshort)xx;
365
seg[1].y2 = 7 + (FXshort)yy;
366
seg[2].x1 = 2 + (FXshort)xx;
367
seg[2].y1 = 6 + (FXshort)yy;
368
seg[2].x2 = 4 + (FXshort)xx;
369
seg[2].y2 = 8 + (FXshort)yy;
370
seg[3].x1 = 4 + (FXshort)xx;
371
seg[3].y1 = 6 + (FXshort)yy;
372
seg[3].x2 = 8 + (FXshort)xx;
373
seg[3].y2 = 2 + (FXshort)yy;
374
seg[4].x1 = 4 + (FXshort)xx;
375
seg[4].y1 = 7 + (FXshort)yy;
376
seg[4].x2 = 8 + (FXshort)xx;
377
seg[4].y2 = 3 + (FXshort)yy;
378
seg[5].x1 = 4 + (FXshort)xx;
379
seg[5].y1 = 8 + (FXshort)yy;
380
seg[5].x2 = 8 + (FXshort)xx;
381
seg[5].y2 = 4 + (FXshort)yy;
382
if (isEnabled()) {
383
if (myCheck == MAYBE) {
384
dc.setForeground(shadowColor);
385
} else {
386
dc.setForeground(textColor);
387
}
388
} else {
389
dc.setForeground(shadowColor);
390
}
391
dc.drawLineSegments(seg, 6);
392
}
393
// draw icon
394
if (myIcon) {
395
if (isEnabled()) {
396
dc.drawIcon(myIcon, LEADSPACE, (height - myIcon->getHeight()) / 2);
397
xx += 5 + myIcon->getWidth();
398
} else {
399
dc.drawIconSunken(myIcon, LEADSPACE, (height - myIcon->getHeight()) / 2);
400
xx += 5 + myIcon->getWidth();
401
}
402
}
403
return 1;
404
}
405
406
407
void
408
MFXMenuCheckIcon::setBoxColor(FXColor clr) {
409
if (clr != myBoxColor) {
410
myBoxColor = clr;
411
update();
412
}
413
}
414
415
416
void
417
MFXMenuCheckIcon::save(FXStream& store) const {
418
FXMenuCommand::save(store);
419
store << myCheck;
420
store << myBoxColor;
421
}
422
423
424
void MFXMenuCheckIcon::load(FXStream& store) {
425
FXMenuCommand::load(store);
426
store >> myCheck;
427
store >> myBoxColor;
428
}
429
430
431
MFXMenuCheckIcon::MFXMenuCheckIcon() :
432
myIcon(nullptr),
433
myCheck(FALSE),
434
myBoxColor(0) {
435
}
436
437