Eclipse SUMO - Simulation of Urban MObility
MFXMenuCheckIcon.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2004-2024 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 //
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
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
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
103  if (myCheck != s) {
104  myCheck = s;
105  update();
106  }
107 }
108 
109 
110 FXbool
112  return myCheck;
113 }
114 
115 
116 FXColor
118  return myBoxColor;
119 }
120 
121 
122 long
123 MFXMenuCheckIcon::onCheck(FXObject*, FXSelector, void*) {
124  setCheck(TRUE);
125  return 1;
126 }
127 
128 
129 long
130 MFXMenuCheckIcon::onUncheck(FXObject*, FXSelector, void*) {
131  setCheck(FALSE);
132  return 1;
133 }
134 
135 
136 long
137 MFXMenuCheckIcon::onUnknown(FXObject*, FXSelector, void*) {
138  setCheck(MAYBE);
139  return 1;
140 }
141 
142 
143 long
144 MFXMenuCheckIcon::onCmdSetValue(FXObject*, FXSelector, void* ptr) {
145  setCheck((FXbool)(FXuval)ptr);
146  return 1;
147 }
148 
149 
150 long
151 MFXMenuCheckIcon::onCmdSetIntValue(FXObject*, FXSelector, void* ptr) {
152  setCheck((FXbool) * ((FXint*)ptr));
153  return 1;
154 }
155 
156 
157 long
158 MFXMenuCheckIcon::onCmdGetIntValue(FXObject*, FXSelector, void* ptr) {
159  *((FXint*)ptr) = getCheck();
160  return 1;
161 }
162 
163 
164 long
165 MFXMenuCheckIcon::onButtonPress(FXObject*, FXSelector, void*) {
166  if (!isEnabled()) {
167  return 0;
168  }
169  return 1;
170 }
171 
172 
173 long
174 MFXMenuCheckIcon::onButtonRelease(FXObject*, FXSelector, void*) {
175  FXbool active = isActive();
176  if (!isEnabled()) {
177  return 0;
178  }
179  // keep menu open
180  //getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
181  if (active) {
182  setCheck(!myCheck);
183  if (target) {
184  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
185  }
186  }
187  return 1;
188 }
189 
190 
191 long
192 MFXMenuCheckIcon::onKeyPress(FXObject*, FXSelector, void* ptr) {
193  FXEvent* event = (FXEvent*)ptr;
194  if (isEnabled() && !(flags & FLAG_PRESSED)) {
195  FXTRACE((200, "%s::onKeyPress %p keysym = 0x%04x state = %04x\n", getClassName(), (void*)this, event->code, event->state));
196  if (event->code == FX::KEY_space || event->code == FX::KEY_KP_Space || event->code == FX::KEY_Return || event->code == FX::KEY_KP_Enter) {
197  flags |= FLAG_PRESSED;
198  return 1;
199  }
200  }
201  return 0;
202 }
203 
204 
205 long
206 MFXMenuCheckIcon::onKeyRelease(FXObject*, FXSelector, void* ptr) {
207  FXEvent* event = (FXEvent*)ptr;
208  if (isEnabled() && (flags & FLAG_PRESSED)) {
209  FXTRACE((200, "%s::onKeyRelease %p keysym = 0x%04x state = %04x\n", getClassName(), (void*)this, event->code, event->state));
210  if (event->code == FX::KEY_space || event->code == FX::KEY_KP_Space || event->code == FX::KEY_Return || event->code == FX::KEY_KP_Enter) {
211  flags &= ~FLAG_PRESSED;
212  setCheck(!myCheck);
213  getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
214  if (target) {
215  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
216  }
217  return 1;
218  }
219  }
220  return 0;
221 }
222 
223 
224 long
225 MFXMenuCheckIcon::onHotKeyPress(FXObject*, FXSelector, void* ptr) {
226  FXTRACE((200, "%s::onHotKeyPress %p\n", getClassName(), (void*)this));
227  handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
228  if (isEnabled() && !(flags & FLAG_PRESSED)) {
229  flags |= FLAG_PRESSED;
230  }
231  return 1;
232 }
233 
234 
235 long
236 MFXMenuCheckIcon::onHotKeyRelease(FXObject*, FXSelector, void*) {
237  FXTRACE((200, "%s::onHotKeyRelease %p\n", getClassName(), (void*)this));
238  if (isEnabled() && (flags & FLAG_PRESSED)) {
239  flags &= ~FLAG_PRESSED;
240  setCheck(!myCheck);
241  getParent()->handle(this, FXSEL(SEL_COMMAND, ID_UNPOST), NULL);
242  if (target) {
243  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
244  }
245  }
246  return 1;
247 }
248 
249 
250 long
251 MFXMenuCheckIcon::onCmdAccel(FXObject*, FXSelector, void*) {
252  if (isEnabled()) {
253  setCheck(!myCheck);
254  if (target) {
255  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)(FXuval)myCheck);
256  }
257  return 1;
258  }
259  return 0;
260 }
261 
262 
263 long
264 MFXMenuCheckIcon::onPaint(FXObject*, FXSelector, void* ptr) {
265  FXEvent* ev = (FXEvent*)ptr;
266  FXDCWindow dc(this, ev);
267  FXint xx, yy;
268  // set xx depending of myIcon
269  if (myIcon) {
270  xx = LEADSPACE + myIcon->getWidth() + 5;
271  } else {
272  xx = LEADSPACE;
273  }
274  // begin draw
275  if (!isEnabled()) {
276  // Grayed out
277  dc.setForeground(backColor);
278  dc.fillRectangle(0, 0, width, height);
279  if (!label.empty()) {
280  yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
281  dc.setFont(font);
282  dc.setForeground(hiliteColor);
283  dc.drawText(xx + 1, yy + 1, label);
284  if (!accel.empty()) {
285  dc.drawText(width - TRAILSPACE - font->getTextWidth(accel) + 1, yy + 1, accel);
286  }
287  if (0 <= hotoff) {
288  dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff) + 1, yy + 2, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
289  }
290  dc.setForeground(shadowColor);
291  dc.drawText(xx, yy, label);
292  if (!accel.empty()) {
293  dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
294  }
295  if (0 <= hotoff) {
296  dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
297  }
298  }
299  } else if (isActive()) {
300  // Active
301  dc.setForeground(selbackColor);
302  dc.fillRectangle(0, 0, width, height);
303  if (!label.empty()) {
304  yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
305  dc.setFont(font);
306  dc.setForeground(isEnabled() ? seltextColor : shadowColor);
307  dc.drawText(xx, yy, label);
308  if (!accel.empty()) {
309  dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
310  }
311  if (0 <= hotoff) {
312  dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
313  }
314  }
315  } else {
316  // Normal
317  dc.setForeground(backColor);
318  dc.fillRectangle(0, 0, width, height);
319  if (!label.empty()) {
320  yy = font->getFontAscent() + (height - font->getFontHeight()) / 2;
321  dc.setFont(font);
322  dc.setForeground(textColor);
323  dc.drawText(xx, yy, label);
324  if (!accel.empty()) {
325  dc.drawText(width - TRAILSPACE - font->getTextWidth(accel), yy, accel);
326  }
327  if (0 <= hotoff) {
328  dc.fillRectangle(xx + font->getTextWidth(&label[0], hotoff), yy + 1, font->getTextWidth(&label[hotoff], wclen(&label[hotoff])), 1);
329  }
330  }
331  }
332  // Draw the box
333  xx = 5;
334  yy = (height - 9) / 2;
335  if (!isEnabled()) {
336  dc.setForeground(backColor);
337  } else {
338  dc.setForeground(myBoxColor);
339  dc.fillRectangle(xx + 1, yy + 1, 8, 8);
340  dc.setForeground(shadowColor);
341  dc.drawRectangle(xx, yy, 9, 9);
342  }
343  // Draw the check (tick)
344  if (myCheck != FALSE) {
345  FXSegment seg[6];
346  seg[0].x1 = 2 + (FXshort)xx;
347  seg[0].y1 = 4 + (FXshort)yy;
348  seg[0].x2 = 4 + (FXshort)xx;
349  seg[0].y2 = 6 + (FXshort)yy;
350  seg[1].x1 = 2 + (FXshort)xx;
351  seg[1].y1 = 5 + (FXshort)yy;
352  seg[1].x2 = 4 + (FXshort)xx;
353  seg[1].y2 = 7 + (FXshort)yy;
354  seg[2].x1 = 2 + (FXshort)xx;
355  seg[2].y1 = 6 + (FXshort)yy;
356  seg[2].x2 = 4 + (FXshort)xx;
357  seg[2].y2 = 8 + (FXshort)yy;
358  seg[3].x1 = 4 + (FXshort)xx;
359  seg[3].y1 = 6 + (FXshort)yy;
360  seg[3].x2 = 8 + (FXshort)xx;
361  seg[3].y2 = 2 + (FXshort)yy;
362  seg[4].x1 = 4 + (FXshort)xx;
363  seg[4].y1 = 7 + (FXshort)yy;
364  seg[4].x2 = 8 + (FXshort)xx;
365  seg[4].y2 = 3 + (FXshort)yy;
366  seg[5].x1 = 4 + (FXshort)xx;
367  seg[5].y1 = 8 + (FXshort)yy;
368  seg[5].x2 = 8 + (FXshort)xx;
369  seg[5].y2 = 4 + (FXshort)yy;
370  if (isEnabled()) {
371  if (myCheck == MAYBE) {
372  dc.setForeground(shadowColor);
373  } else {
374  dc.setForeground(textColor);
375  }
376  } else {
377  dc.setForeground(shadowColor);
378  }
379  dc.drawLineSegments(seg, 6);
380  }
381  // draw icon
382  if (myIcon) {
383  if (isEnabled()) {
384  dc.drawIcon(myIcon, LEADSPACE, (height - myIcon->getHeight()) / 2);
385  xx += 5 + myIcon->getWidth();
386  } else {
387  dc.drawIconSunken(myIcon, LEADSPACE, (height - myIcon->getHeight()) / 2);
388  xx += 5 + myIcon->getWidth();
389  }
390  }
391  return 1;
392 }
393 
394 
395 void
397  if (clr != myBoxColor) {
398  myBoxColor = clr;
399  update();
400  }
401 }
402 
403 
404 void
405 MFXMenuCheckIcon::save(FXStream& store) const {
406  FXMenuCommand::save(store);
407  store << myCheck;
408  store << myBoxColor;
409 }
410 
411 
412 void MFXMenuCheckIcon::load(FXStream& store) {
413  FXMenuCommand::load(store);
414  store >> myCheck;
415  store >> myBoxColor;
416 }
417 
418 
420  myIcon(nullptr),
421  myCheck(FALSE),
422  myBoxColor(0) {
423 }
#define LEADSPACE
#define TRAILSPACE
FXDEFMAP(MFXMenuCheckIcon) MFXMenuCheckIconMap[]
long onHotKeyPress(FXObject *, FXSelector, void *)
long onUnknown(FXObject *, FXSelector, void *)
long onKeyRelease(FXObject *, FXSelector, void *)
void setBoxColor(FXColor clr)
Set the box background color.
virtual void load(FXStream &store)
Load menu from a stream.
MFXMenuCheckIcon()
default constructor
long onCheck(FXObject *, FXSelector, void *)
long onCmdSetIntValue(FXObject *, FXSelector, void *)
virtual FXint getDefaultWidth()
Return default width.
long onHotKeyRelease(FXObject *, FXSelector, void *)
FXColor myBoxColor
Box color.
long onCmdAccel(FXObject *, FXSelector, void *)
long onButtonPress(FXObject *, FXSelector, void *)
const FXIcon * myIcon
Icon.
long onCmdSetValue(FXObject *, FXSelector, void *)
FXColor getBoxColor() const
Get the box background color.
FXuchar myCheck
State of menu.
long onUncheck(FXObject *, FXSelector, void *)
long onKeyPress(FXObject *, FXSelector, void *)
long onPaint(FXObject *, FXSelector, void *)
virtual void save(FXStream &store) const
Save menu to a stream.
FXbool getCheck() const
Get check state (TRUE, FALSE or MAYBE)
long onCmdGetIntValue(FXObject *, FXSelector, void *)
virtual FXint getDefaultHeight()
Return default height.
long onButtonRelease(FXObject *, FXSelector, void *)
void setCheck(FXbool s=TRUE)
Set check state (TRUE, FALSE or MAYBE)
Definition: json.hpp:4471