SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FXRealSpinDial.cpp
Go to the documentation of this file.
1 /********************************************************************************
2 * *
3 * R e a l - V a l u e d S p i n n e r / D i a l W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 2004 by Bill Baxter. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FXRealSpinDial.cpp 11451 2011-11-02 09:07:49Z behrisch $ *
23 ********************************************************************************/
24 /* =========================================================================
25  * included modules
26  * ======================================================================= */
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <fx.h>
34 #include "xincs.h"
35 #include "fxver.h"
36 #include "fxdefs.h"
37 #include "fxkeys.h"
38 #include "FXStream.h"
39 #include "FXString.h"
40 #include "FXSize.h"
41 #include "FXPoint.h"
42 #include "FXRectangle.h"
43 #include "FXRegistry.h"
44 #include "FXAccelTable.h"
45 #include "FXApp.h"
46 #include "FXLabel.h"
47 #include "FXTextField.h"
48 #include "FXDial.h"
49 #include "FXRealSpinDial.h"
50 
51 #include <float.h>
52 
53 #ifdef CHECK_MEMORY_LEAKS
54 #include <foreign/nvwa/debug_new.h>
55 #endif // CHECK_MEMORY_LEAKS
56 /*
57  Notes:
58  - Based originally on Lyle's FXSpinner.
59  - Can use with spin buttons, dial, or both, and with or without text
60  - Three increment levels, fine, normal, and coarse. Access different modes
61  with CONTROL key (fine control) and SHIFT key (coarse mode). Modifiers
62  affect all of up/down keys, mousewheel, dial and spinbuttons.
63  - Can specify display format for text either as a precision,showExponent pair
64  or an sprintf format string. (String format can include extra text like '$'!)
65  - Wheel mouse increment/decrement in even multiples of fine/norm/coarse scales.
66  (Key modifers sometimes require mouse motion to kick in because FOX doesn't
67  have a [public] way to query the key state asynchronously. Hacked extern to
68  FOX's internal WIN32 function for querying this, so it works on Win32)
69  - Dial warps the pointer at the edge of the screen so you don't run out of
70  screen real estate.
71 */
72 #define DIALINCR 160
73 #define DIALMULT 40
74 #define DIALWIDTH 12
75 #define BUTTONWIDTH 12
76 #define GAPWIDTH 1
77 
78 #define INTMAX 2147483647
79 #define INTMIN (-INTMAX-1)
80 
81 #define SPINDIAL_MASK (SPINDIAL_CYCLIC|SPINDIAL_NOTEXT|SPINDIAL_NOBUTTONS|SPINDIAL_NODIAL|SPINDIAL_NOMAX|SPINDIAL_NOMIN|SPINDIAL_LOG)
82 
83 using namespace FX;
84 
85 /*******************************************************************************/
86 /* Custom FXDial subclass */
87 /*******************************************************************************/
88 namespace FX {
89 class FXRealSpinDialDial : public FXDial {
90  FXDECLARE(FXRealSpinDialDial)
91 protected:
93 private:
95  FXRealSpinDialDial& operator=(const FXRealSpinDialDial&);
96 public:
97  //long onDefault(FXObject*,FXSelector,void* );
98  long onKey(FXObject*, FXSelector, void*);
99  long onButtonPress(FXObject*, FXSelector, void*);
100  long onButtonRelease(FXObject*, FXSelector, void*);
101  long onRightButtonPress(FXObject*, FXSelector, void*);
102  long onRightButtonRelease(FXObject*, FXSelector, void*);
103  long onMotion(FXObject*, FXSelector, void*);
104  long onAuto(FXObject*, FXSelector, void*);
105  enum {
106  ID_AUTOSPIN = FXDial::ID_LAST,
107  ID_LAST
108  };
109 public:
110 
112  FXRealSpinDialDial(FXComposite* p, FXObject* tgt = NULL, FXSelector sel = 0, FXuint opts = DIAL_NORMAL,
113  FXint x = 0, FXint y = 0, FXint w = 0, FXint h = 0,
114  FXint pl = DEFAULT_PAD, FXint pr = DEFAULT_PAD, FXint pt = DEFAULT_PAD, FXint pb = DEFAULT_PAD):
115  FXDial(p, tgt, sel, opts, x, y, w, h, pl, pr, pt, pb) {}
116 
117 };
118 
119 FXDEFMAP(FXRealSpinDialDial) FXSpinDialMap[] = {
120  FXMAPFUNC(SEL_KEYPRESS, 0, FXRealSpinDialDial::onKey),
121  FXMAPFUNC(SEL_KEYRELEASE, 0, FXRealSpinDialDial::onKey),
122  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, FXRealSpinDialDial::onButtonPress),
123  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, FXRealSpinDialDial::onRightButtonRelease),
124  FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, FXRealSpinDialDial::onRightButtonPress),
125  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, FXRealSpinDialDial::onButtonRelease),
126  FXMAPFUNC(SEL_MOTION, 0, FXRealSpinDialDial::onMotion),
127 
129 
130  //FXMAPFUNC(SEL_KEYPRESS,0, FXRealSpinDialDial::onKeyPress),
131  //FXMAPFUNC(SEL_KEYRELEASE,0,FXRealSpinDialDial::onKeyRelease),
132 };
133 FXIMPLEMENT(FXRealSpinDialDial, FXDial, FXSpinDialMap, ARRAYNUMBER(FXSpinDialMap))
134 //FXIMPLEMENT(FXRealSpinDialDial,FXDial,0,0)
135 
136 //long FXRealSpinDialDial::onDefault(FXObject*o,FXSelector s,void*p )
137 //{
138 // printf("DEFAULT!\n");
139 // if (target) return target->handle(o,s,p);
140 // return 0;
141 //}
142 long FXRealSpinDialDial::onKey(FXObject* o, FXSelector s, void* p) {
143  if (target) {
144  return target->handle(o, s, p);
145  }
146  return 0;
147 }
148 long FXRealSpinDialDial::onButtonPress(FXObject* o, FXSelector s, void* p) {
149  grabKeyboard();
150  return FXDial::onLeftBtnPress(o, s, p);
151 }
152 long FXRealSpinDialDial::onButtonRelease(FXObject* o, FXSelector s, void* p) {
153  ungrabKeyboard();
154  return FXDial::onLeftBtnRelease(o, s, p);
155 }
156 long FXRealSpinDialDial::onRightButtonPress(FXObject* /*o*/, FXSelector /*s*/, void* p) {
157  if (isEnabled()) {
158  grab();
159  grabKeyboard();
160  //if(target && target->handle(this,FXSEL(SEL_RIGHTBUTTONPRESS,message),ptr)) return 1;
161  FXEvent* event = (FXEvent*)p;
162  if (options & DIAL_HORIZONTAL) {
163  dragpoint = event->win_x;
164  } else {
165  dragpoint = event->win_y;
166  }
167  getApp()->addTimeout(this, ID_AUTOSPIN, getApp()->getScrollSpeed());
168  }
169  return 1;
170 }
171 long FXRealSpinDialDial::onRightButtonRelease(FXObject* /*o*/, FXSelector /*s*/, void* /*p*/) {
172  ungrab();
173  ungrabKeyboard();
174  getApp()->removeTimeout(this, ID_AUTOSPIN);
175  if (isEnabled()) {
176  //if(target && target->handle(this,FXSEL(SEL_RIGHTBUTTONRELEASE,message),p)) return 1;
177  }
178  return 1;
179 
180 }
181 long FXRealSpinDialDial::onAuto(FXObject* /*o*/, FXSelector /*s*/, void* /*p*/) {
182  getApp()->addTimeout(this, ID_AUTOSPIN, getApp()->getScrollSpeed());
183  setValue(getValue() + int((dragpoint - dragpos) / float(5)));
184  int v = getValue();
185  if (target) {
186  target->handle(this, FXSEL(SEL_CHANGED, message), &v);
187  }
188  return 1;
189 }
190 
191 long FXRealSpinDialDial::onMotion(FXObject* o, FXSelector s, void* p) {
192  if (!isEnabled()) {
193  return 0;
194  }
195  if (target && target->handle(this, FXSEL(SEL_MOTION, message), p)) {
196  return 1;
197  }
198 
199  FXbool bJump = FALSE;
200  FXEvent* e = (FXEvent*)p;
201  if (!(flags & FLAG_PRESSED)) { // not doing clickdrag
202  dragpos = e->win_y;
203  }
204  FXWindow* rootWin = getApp()->getRootWindow();
205  FXint x = e->root_x, y = e->root_y;
206  if (e->root_x >= rootWin->getWidth() - 1) {
207  x -= 40;
208  dragpoint -= 40;
209  bJump = TRUE;
210  } else if (e->root_x <= 10) {
211  x += 40;
212  dragpoint += 40;
213  bJump = TRUE;
214  }
215  if (e->root_y >= rootWin->getHeight() - 1) {
216  y -= 40;
217  dragpoint -= 40;
218  bJump = TRUE;
219  } else if (e->root_y <= 10) {
220  y += 40;
221  dragpoint += 40;
222  bJump = TRUE;
223  }
224  if (bJump) {
225  rootWin->setCursorPosition(x, y);
226  return 1;
227  } else {
228  return FXDial::onMotion(o, s, p);
229  }
230 }
231 
232 }
233 
234 /*******************************************************************************/
235 /* Custom FXArrowButton subclass */
236 /*******************************************************************************/
237 namespace FX {
239  FXDECLARE(FXRealSpinDialBtn)
240 protected:
242 private:
244  FXRealSpinDialBtn& operator=(const FXRealSpinDialBtn&);
245 public:
246  //long onDefault(FXObject*,FXSelector,void* );
247  long onKey(FXObject*, FXSelector, void*);
248  long onButtonPress(FXObject*, FXSelector, void*);
249  long onButtonRelease(FXObject*, FXSelector, void*);
250  enum {
251  ID_AUTOSPIN = FXDial::ID_LAST,
252  ID_LAST
253  };
254 public:
255 
257  FXRealSpinDialBtn(FXComposite* p, FXObject* tgt = NULL, FXSelector sel = 0,
258  FXuint opts = ARROW_NORMAL,
259  FXint x = 0, FXint y = 0, FXint w = 0, FXint h = 0,
260  FXint pl = DEFAULT_PAD, FXint pr = DEFAULT_PAD, FXint pt = DEFAULT_PAD, FXint pb = DEFAULT_PAD):
261  FXArrowButton(p, tgt, sel, opts, x, y, w, h, pl, pr, pt, pb) {}
262 
263 };
264 
265 FXDEFMAP(FXRealSpinDialBtn) FXSpinDialBtnMap[] = {
266  FXMAPFUNC(SEL_KEYPRESS, 0, FXRealSpinDialBtn::onKey),
267  FXMAPFUNC(SEL_KEYRELEASE, 0, FXRealSpinDialBtn::onKey),
268  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, FXRealSpinDialBtn::onButtonPress),
269  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, FXRealSpinDialBtn::onButtonRelease),
270 
271 
272  //FXMAPFUNC(SEL_KEYPRESS,0, FXRealSpinDialBtn::onKeyPress),
273  //FXMAPFUNC(SEL_KEYRELEASE,0,FXRealSpinDialBtn::onKeyRelease),
274 };
275 FXIMPLEMENT(FXRealSpinDialBtn, FXArrowButton, FXSpinDialBtnMap, ARRAYNUMBER(FXSpinDialBtnMap))
276 //FXIMPLEMENT(FXRealSpinDialBtn,FXDial,0,0)
277 
278 //long FXRealSpinDialBtn::onDefault(FXObject*o,FXSelector s,void*p )
279 //{
280 // printf("DEFAULT!\n");
281 // if (target) return target->handle(o,s,p);
282 // return 0;
283 //}
284 long FXRealSpinDialBtn::onKey(FXObject* o, FXSelector s, void* p) {
285  if (target) {
286  return target->handle(o, s, p);
287  }
288  return 0;
289 }
290 long FXRealSpinDialBtn::onButtonPress(FXObject* o, FXSelector s, void* p) {
291  grabKeyboard();
292  return FXArrowButton::onLeftBtnPress(o, s, p);
293 }
294 long FXRealSpinDialBtn::onButtonRelease(FXObject* o, FXSelector s, void* p) {
295  ungrabKeyboard();
296  return FXArrowButton::onLeftBtnRelease(o, s, p);
297 }
298 
299 
300 }
301 
302 
303 /*******************************************************************************/
304 /* FXTextField subclass */
305 /*******************************************************************************/
306 
307 namespace FX {
309  FXDECLARE(FXRealSpinDialText)
310 protected:
312 private:
314  FXRealSpinDialText& operator=(const FXRealSpinDialText&);
315 public:
316  long onCmdSetRealValue(FXObject*, FXSelector, void*);
317  long onMotion(FXObject*, FXSelector, void*);
318  enum {
319  ID_LAST = FXTextField::ID_LAST
320  };
321  enum {
322  FLAG_FMTSTRING = 0x1
323  };
324 public:
325 
327  FXRealSpinDialText(FXComposite* p, FXint ncols, FXObject* tgt = NULL, FXSelector sel = 0,
328  FXuint opts = TEXTFIELD_NORMAL,
329  FXint x = 0, FXint y = 0, FXint w = 0, FXint h = 0, FXint
330  pl = DEFAULT_PAD, FXint pr = DEFAULT_PAD, FXint pt = DEFAULT_PAD, FXint pb = DEFAULT_PAD
331  ) :
332  FXTextField(p, ncols, tgt, sel, opts, x, y, w, h, pl, pr, pt, pb),
333  precision(3),
334  exponent(FALSE),
335  flags(0) {}
336 
337  void setNumberFormat(FXint prec, FXbool bExp = FALSE) {
338  precision = prec;
339  exponent = bExp;
340  flags &= ~FLAG_FMTSTRING;
341  }
342  FXint getNumberFormatPrecision() const {
343  return precision;
344  }
345  FXbool getNumberFormatExponent() const {
346  return exponent;
347  }
348  void setFormatString(const FXchar* fmt) {
349  fmtString = fmt;
350  flags |= FLAG_FMTSTRING;
351  }
352  FXString getNumberFormatString() const {
353  return fmtString;
354  }
355 
356 protected:
357  FXint precision;
358  FXbool exponent;
359  FXString fmtString;
360  FXuint flags;
361 };
362 
363 FXDEFMAP(FXRealSpinDialText) FXSpinDialTextMap[] = {
364  FXMAPFUNC(SEL_MOTION, 0, FXRealSpinDialText::onMotion),
365  FXMAPFUNC(SEL_COMMAND, FXWindow::ID_SETREALVALUE, FXRealSpinDialText::onCmdSetRealValue),
366 };
367 FXIMPLEMENT(FXRealSpinDialText, FXTextField, FXSpinDialTextMap, ARRAYNUMBER(FXSpinDialTextMap))
368 
369 long FXRealSpinDialText::onMotion(FXObject* o, FXSelector s, void* ptr) {
370  // Forward motion events so we can monitor key state. We don't get the modifier
371  // keys themselves if we aren't focused, so this seems the best we can do.
372  if (!isEnabled()) {
373  return 0;
374  }
375  if (target && target->handle(this, FXSEL(SEL_MOTION, message), ptr)) {
376  return 1;
377  }
378  return FXTextField::onMotion(o, s, ptr);
379 }
380 long FXRealSpinDialText::onCmdSetRealValue(FXObject* /*o*/, FXSelector /*s*/, void* ptr) {
381  // setText(FXStringVal(*((FXdouble*)ptr)));
382  if (flags & FLAG_FMTSTRING) {
383  setText(FXStringFormat(fmtString.text(), *((FXdouble*)ptr)));
384  } else {
385  setText(FXStringVal(*((FXdouble*)ptr), precision, exponent));
386  }
387  return 1;
388 }
389 
390 }
391 
392 /*******************************************************************************/
393 /* FXRealSpinDial */
394 /*******************************************************************************/
395 
396 namespace FX {
397 
398 // Message map
399 FXDEFMAP(FXRealSpinDial) FXRealSpinDialMap[] = {
400  FXMAPFUNC(SEL_KEYPRESS, 0, FXRealSpinDial::onKeyPress),
401  FXMAPFUNC(SEL_KEYRELEASE, 0, FXRealSpinDial::onKeyRelease),
402  FXMAPFUNC(SEL_MOTION, 0, FXRealSpinDial::onMotion),
403  FXMAPFUNC(SEL_MOTION, FXRealSpinDial::ID_ENTRY, FXRealSpinDial::onMotion),
404  FXMAPFUNC(SEL_MOTION, FXRealSpinDial::ID_DIAL, FXRealSpinDial::onMotion),
406  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_ENTRY, FXRealSpinDial::onCmdEntry),
407  FXMAPFUNC(SEL_CHANGED, FXRealSpinDial::ID_ENTRY, FXRealSpinDial::onChgEntry),
408  FXMAPFUNC(SEL_UPDATE, FXRealSpinDial::ID_DIAL, FXRealSpinDial::onUpdDial),
409  FXMAPFUNC(SEL_CHANGED, FXRealSpinDial::ID_DIAL, FXRealSpinDial::onChgDial),
410  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_DIAL, FXRealSpinDial::onCmdDial),
411  FXMAPFUNC(SEL_MOUSEWHEEL, FXRealSpinDial::ID_ENTRY, FXRealSpinDial::onMouseWheel),
412  FXMAPFUNC(SEL_MOUSEWHEEL, FXRealSpinDial::ID_DIAL, FXRealSpinDial::onMouseWheel),
415  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_SETVALUE, FXRealSpinDial::onCmdSetValue),
416  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_SETINTVALUE, FXRealSpinDial::onCmdSetIntValue),
417  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_GETINTVALUE, FXRealSpinDial::onCmdGetIntValue),
418  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_SETINTRANGE, FXRealSpinDial::onCmdSetIntRange),
419  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_GETINTRANGE, FXRealSpinDial::onCmdGetIntRange),
420  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_SETREALVALUE, FXRealSpinDial::onCmdSetRealValue),
421  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_GETREALVALUE, FXRealSpinDial::onCmdGetRealValue),
422  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_SETREALRANGE, FXRealSpinDial::onCmdSetRealRange),
423  FXMAPFUNC(SEL_COMMAND, FXRealSpinDial::ID_GETREALRANGE, FXRealSpinDial::onCmdGetRealRange),
428 };
429 
430 
431 // Object implementation
432 FXIMPLEMENT(FXRealSpinDial, FXPacker, FXRealSpinDialMap, ARRAYNUMBER(FXRealSpinDialMap))
433 
434 
435 // Construct spinner out of two buttons and a text field
437  flags = (flags | FLAG_ENABLED | FLAG_SHOWN)&~FLAG_UPDATE;
438  textField = (FXRealSpinDialText*) - 1L;
439  dial = (FXDial*) - 1L;
440  upButton = (FXRealSpinDialBtn*) - 1L;
441  downButton = (FXRealSpinDialBtn*) - 1L;
442  range[0] = -DBL_MAX;
443  range[1] = DBL_MAX;
444  incr[0] = 0.1;
445  incr[1] = 1.0;
446  incr[2] = 10;
447  pos = 1;
448  dialpos = 0;
449 }
450 
451 
452 // Construct spinner out of dial and a text field
453 FXRealSpinDial::FXRealSpinDial(FXComposite* p, FXint cols, FXObject* tgt, FXSelector sel, FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb):
454  FXPacker(p, opts&~(FRAME_RIDGE), x, y, w, h, 0, 0, 0, 0, 0, 0) {
455  flags = (flags | FLAG_ENABLED | FLAG_SHOWN)&~FLAG_UPDATE;
456  target = tgt;
457  message = sel;
458  dial = new FXRealSpinDialDial(this, this, ID_DIAL, DIAL_VERTICAL, 0, 0, 0, 0, 0, 0, 0, 0);
459  dial->setNotchSpacing(450);
460  dial->setRevolutionIncrement(DIALINCR);
461  upButton = new FXRealSpinDialBtn(this, this, ID_INCREMENT, FRAME_RAISED | FRAME_THICK | ARROW_UP | ARROW_REPEAT, 0, 0, 0, 0, 0, 0, 0, 0);
462  downButton = new FXRealSpinDialBtn(this, this, ID_DECREMENT, FRAME_RAISED | FRAME_THICK | ARROW_DOWN | ARROW_REPEAT, 0, 0, 0, 0, 0, 0, 0, 0);
463  textField = new FXRealSpinDialText(this, cols, this, ID_ENTRY, (opts & FRAME_RIDGE) | TEXTFIELD_REAL | JUSTIFY_RIGHT, 0, 0, 0, 0, pl, pr, pt, pb);
464  textField->setText("0");
465  range[0] = (options & SPINDIAL_NOMIN) ? -DBL_MAX : 0;
466  range[1] = (options & SPINDIAL_NOMAX) ? DBL_MAX : 100;
467  dial->setRange(INTMIN, INTMAX);
468  dialpos = dial->getValue();
469  incr[0] = 0.1;
470  incr[1] = 1.0;
471  incr[2] = 10;
472  pos = 0;
473  keystate = 0;
474 }
475 
476 
477 // Get default width
479  FXint tw = 0;
480  if (!(options & SPINDIAL_NOTEXT)) {
481  tw = textField->getDefaultWidth();
482  }
483  return tw + DIALWIDTH + GAPWIDTH + (border << 1);
484 }
485 
486 
487 // Get default height
489  return textField->getDefaultHeight() + (border << 1);
490 }
491 
492 
493 // Create window
496 }
497 
498 
499 // Enable the widget
501  if (!(flags & FLAG_ENABLED)) {
503  textField->enable();
504  dial->enable();
505  }
506 }
507 
508 
509 // Disable the widget
511  if (flags & FLAG_ENABLED) {
513  textField->disable();
514  dial->disable();
515  }
516 }
517 
518 
519 // Recompute layout
521  FXint dialWidth, dialHeight, buttonWidth, buttonHeight, textHeight;
522 
523  textHeight = height - 2 * border;
524  dialHeight = textHeight;
525  buttonHeight = textHeight >> 1;
526 
527  FXuint hideOpts = SPINDIAL_NOTEXT | SPINDIAL_NODIAL | SPINDIAL_NOBUTTONS;
528  if ((options & hideOpts) == hideOpts) {
529  flags &= ~FLAG_DIRTY;
530  return; // nothing to layout
531  }
532 
533  FXint right = width - border;
534 
535  if (options & SPINDIAL_NOTEXT) {
536  // Dial takes up the extra space if shown, otherwise spinbuttons
537  if (!(options & SPINDIAL_NODIAL)) {
538  // HAS DIAL
539  int left = border;
540  if (!(options & SPINDIAL_NOBUTTONS)) {
541  FXint bw = BUTTONWIDTH;
542  upButton->position(border, border, bw, buttonHeight);
543  downButton->position(border, height - buttonHeight - border, bw, buttonHeight);
544  left += bw + GAPWIDTH;
545  }
546  dial->position(left, border, right - left, dialHeight);
547  } else {
548  upButton->position(border, border, right - border, buttonHeight);
549  downButton->position(border, height - buttonHeight - border, right - border, buttonHeight);
550  }
551  } else {
552  // dial/buttons are default width, text stretches to fill the rest
553  dialWidth = buttonWidth = 0;
554  if (!(options & SPINDIAL_NODIAL)) {
555  FXint w = DIALWIDTH;
556  dial->position(right - w, border, w, dialHeight);
557  right -= w + GAPWIDTH;
558  }
559  if (!(options & SPINDIAL_NOBUTTONS)) {
560  FXint w = BUTTONWIDTH;
561  upButton->position(right - w, border, w, buttonHeight);
562  downButton->position(right - w, height - buttonHeight - border, w, buttonHeight);
563  right -= w + GAPWIDTH;
564  }
565  textField->position(border, border, right - border, textHeight);
566  }
567  flags &= ~FLAG_DIRTY;
568 }
569 
570 
571 // Respond to dial message
572 long FXRealSpinDial::onUpdDial(FXObject* sender, FXSelector, void*) {
573  if (isEnabled() && ((options & SPINDIAL_CYCLIC) || (pos <= range[1]))) {
574  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
575  } else {
576  sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
577  }
578  return 1;
579 }
580 
581 
582 // Respond to dial message
583 long FXRealSpinDial::onChgDial(FXObject* /*p*/, FXSelector /*sel*/, void* /*ptr*/) {
584  if (!isEnabled()) {
585  return 0;
586  }
587  FXdouble newpos;
588  FXdouble inc;
589  if (FXApp::instance()->getKeyState(CONTROLMASK)) {
590  inc = incr[0];
591  } else if (FXApp::instance()->getKeyState(SHIFTMASK)) {
592  inc = incr[2];
593  } else {
594  inc = incr[1];
595  }
596  FXint dialdelta = dial->getValue() - dialpos;
597  if (options & SPINDIAL_LOG) {
598  newpos = pos * pow(inc , DIALMULT * FXdouble(dialdelta) / DIALINCR);
599  } else {
600  newpos = pos + DIALMULT * inc * (dialdelta) / DIALINCR;
601  }
602  // Now clamp newpos.
603  if (dialdelta > 0) {
604  if (options & SPINDIAL_LOG) {
605  if (options & SPINDIAL_CYCLIC && newpos > range[1]) {
606  FXdouble lr0 = log(range[0]), lr1 = log(range[1]), lnp = log(newpos);
607  newpos = exp(lr0 + fmod(lnp - lr0, lr1 - lr0)) ;
608  }
609  } else {
610  if (options & SPINDIAL_CYCLIC) {
611  newpos = range[0] + fmod(newpos - range[0], range[1] - range[0] + 1) ;
612  }
613  }
614  } else {
615  if (options & SPINDIAL_LOG) {
616  if (options & SPINDIAL_CYCLIC && newpos < range[0]) {
617  FXdouble lr0 = log(range[0]), lr1 = log(range[1]), lpos = log(pos);
618  FXdouble span = lr1 - lr0;
619  newpos = exp(lr0 + fmod(lpos - lr0 + 1 + (span - inc), span));
620  }
621  } else {
622  if (options & SPINDIAL_CYCLIC) {
623  newpos = range[0] + fmod(pos + (range[1] - range[0] + 1 + (newpos - pos) - range[0]) , range[1] - range[0] + 1);
624  }
625  }
626  }
627  setValue(newpos);
628  if (target) {
629  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
630  }
631  dialpos = dial->getValue();
632  return 1;
633 }
634 
635 // Respond to dial message
636 long FXRealSpinDial::onCmdDial(FXObject*, FXSelector /*sel*/, void*) {
637  if (!isEnabled()) {
638  return 0;
639  }
640  // if(target) target->handle(this,FXSEL(SEL_COMMAND,message),(void*)&pos);
641  dialpos = dial->getValue() % DIALINCR;
642  dial->setValue(dialpos);
643  return 1;
644 }
645 
646 
647 // Respond to increment message
648 long FXRealSpinDial::onUpdIncrement(FXObject* sender, FXSelector, void*) {
649  if (isEnabled() && ((options & REALSPIN_CYCLIC) || (pos < range[1]))) {
650  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
651  } else {
652  sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
653  }
654  return 1;
655 }
656 
657 
658 // Respond to increment message
659 long FXRealSpinDial::onCmdIncrement(FXObject*, FXSelector, void*) {
660  if (!isEnabled()) {
661  return 0;
662  }
663  FXint mode;
664  if (keystate & CONTROLMASK) {
665  mode = SPINDIAL_INC_FINE;
666  } else if (keystate & SHIFTMASK) {
667  mode = SPINDIAL_INC_COARSE;
668  } else {
669  mode = SPINDIAL_INC_NORMAL;
670  }
671  increment(mode);
672  if (target) {
673  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
674  }
675  return 1;
676 }
677 
678 
679 // Disable decrement if at low end already
680 long FXRealSpinDial::onUpdDecrement(FXObject* sender, FXSelector, void*) {
681  if (isEnabled() && ((options & REALSPIN_CYCLIC) || (range[0] < pos))) {
682  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
683  } else {
684  sender->handle(this, FXSEL(SEL_COMMAND, ID_DISABLE), NULL);
685  }
686  return 1;
687 }
688 
689 
690 // Respond to decrement message
691 long FXRealSpinDial::onCmdDecrement(FXObject*, FXSelector, void*) {
692  if (!isEnabled()) {
693  return 0;
694  }
695  FXint mode;
696  if (keystate & CONTROLMASK) {
697  mode = SPINDIAL_INC_FINE;
698  } else if (keystate & SHIFTMASK) {
699  mode = SPINDIAL_INC_COARSE;
700  } else {
701  mode = SPINDIAL_INC_NORMAL;
702  }
703  decrement(mode);
704  if (target) {
705  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
706  }
707  return 1;
708 }
709 
710 
711 
712 // Update from text field
713 long FXRealSpinDial::onUpdEntry(FXObject*, FXSelector, void*) {
714  return target && target->handle(this, FXSEL(SEL_UPDATE, message), NULL);
715 }
716 
717 long FXRealSpinDial::onMouseWheel(FXObject* /*o*/, FXSelector /*s*/, void* p) {
718  FXint mode;
719  keystate = ((FXEvent*)p)->state;
720  if (keystate & CONTROLMASK) {
721  mode = SPINDIAL_INC_FINE;
722  } else if (keystate & SHIFTMASK) {
723  mode = SPINDIAL_INC_COARSE;
724  } else {
725  mode = SPINDIAL_INC_NORMAL;
726  }
727  if (((FXEvent*)p)->code > 0) {
728  increment(mode);
729  } else {
730  decrement(mode);
731  }
732  if (target) {
733  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
734  }
735  return 1;
736 }
737 
738 // Text field changed
739 long FXRealSpinDial::onChgEntry(FXObject*, FXSelector, void*) {
740  register FXdouble value = FXDoubleVal(textField->getText());
741  if (value < range[0]) {
742  value = range[0];
743  }
744  if (value > range[1]) {
745  value = range[1];
746  }
747  if (value != pos) {
748  pos = value;
749  if (target) {
750  target->handle(this, FXSEL(SEL_CHANGED, message), (void*)&pos);
751  }
752  }
753  return 1;
754 }
755 
756 
757 // Text field command
758 long FXRealSpinDial::onCmdEntry(FXObject*, FXSelector, void*) {
759  textField->setText(FXStringVal(pos)); // Put back adjusted value
760  if (target) {
761  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
762  }
763  return 1;
764 }
765 
766 
767 // Keyboard press
768 long FXRealSpinDial::onKeyPress(FXObject* sender, FXSelector sel, void* ptr) {
769  FXEvent* event = (FXEvent*)ptr;
770  if (!isEnabled()) {
771  return 0;
772  }
773  keystate = event->state;
774  if (target && target->handle(this, FXSEL(SEL_KEYPRESS, message), ptr)) {
775  return 1;
776  }
777  FXint mode;
778  if (keystate & CONTROLMASK) {
779  mode = SPINDIAL_INC_FINE;
780  } else if (keystate & SHIFTMASK) {
781  mode = SPINDIAL_INC_COARSE;
782  } else {
783  mode = SPINDIAL_INC_NORMAL;
784  }
785  switch (event->code) {
786  case KEY_Up:
787  case KEY_KP_Up:
788  increment(mode);
789  if (target) {
790  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
791  }
792  return 1;
793  case KEY_Down:
794  case KEY_KP_Down:
795  decrement(mode);
796  if (target) {
797  target->handle(this, FXSEL(SEL_COMMAND, message), (void*)&pos);
798  }
799  return 1;
800  default:
801  return textField->handle(sender, sel, ptr);
802  }
803  return 0;
804 }
805 
806 
807 // Keyboard release
808 long FXRealSpinDial::onKeyRelease(FXObject* sender, FXSelector sel, void* ptr) {
809  FXEvent* event = (FXEvent*)ptr;
810  if (!isEnabled()) {
811  return 0;
812  }
813  keystate = event->state;
814  if (target && target->handle(this, FXSEL(SEL_KEYRELEASE, message), ptr)) {
815  return 1;
816  }
817  switch (event->code) {
818  case KEY_Up:
819  case KEY_KP_Up:
820  case KEY_Down:
821  case KEY_KP_Down:
822  return 1;
823  default:
824  return textField->handle(sender, sel, ptr);
825  }
826  return 0;
827 }
828 
829 // Mouse motion
830 long FXRealSpinDial::onMotion(FXObject* /*sender*/, FXSelector /*sel*/, void* ptr) {
831  if (!isEnabled()) {
832  return 0;
833  }
834  keystate = ((FXEvent*)ptr)->state;
835  return 0;
836 }
837 
838 // Update value from a message
839 long FXRealSpinDial::onCmdSetValue(FXObject*, FXSelector, void* ptr) {
840  setValue((FXdouble)(size_t)ptr);
841  return 1;
842 }
843 
844 
845 // Update value from a message
846 long FXRealSpinDial::onCmdSetIntValue(FXObject*, FXSelector, void* ptr) {
847  setValue(FXdouble(*((FXint*)ptr)));
848  return 1;
849 }
850 
851 
852 // Obtain value from spinner
853 long FXRealSpinDial::onCmdGetIntValue(FXObject*, FXSelector, void* ptr) {
854  *((FXint*)ptr) = (FXint)getValue();
855  return 1;
856 }
857 
858 
859 // Update range from a message
860 long FXRealSpinDial::onCmdSetIntRange(FXObject*, FXSelector, void* ptr) {
861  FXdouble lo = (FXdouble)((FXint*)ptr)[0];
862  FXdouble hi = (FXdouble)((FXint*)ptr)[1];
863  setRange(lo, hi);
864  return 1;
865 }
866 
867 
868 // Get range with a message
869 long FXRealSpinDial::onCmdGetIntRange(FXObject*, FXSelector, void* ptr) {
870  ((FXdouble*)ptr)[0] = range[0];
871  ((FXdouble*)ptr)[1] = range[1];
872  return 1;
873 }
874 
875 
876 // Update value from a message
877 long FXRealSpinDial::onCmdSetRealValue(FXObject*, FXSelector, void* ptr) {
878  setValue(*((FXdouble*)ptr));
879  return 1;
880 }
881 
882 
883 // Obtain value from spinner
884 long FXRealSpinDial::onCmdGetRealValue(FXObject*, FXSelector, void* ptr) {
885  *((FXdouble*)ptr) = getValue();
886  return 1;
887 }
888 
889 
890 // Update range from a message
891 long FXRealSpinDial::onCmdSetRealRange(FXObject*, FXSelector, void* ptr) {
892  setRange(((FXdouble*)ptr)[0], ((FXdouble*)ptr)[1]);
893  return 1;
894 }
895 
896 
897 // Get range with a message
898 long FXRealSpinDial::onCmdGetRealRange(FXObject*, FXSelector, void* ptr) {
899  getRange(((FXdouble*)ptr)[0], ((FXdouble*)ptr)[1]);
900  return 1;
901 }
902 
903 
904 
905 // Increment spinner
906 void FXRealSpinDial::increment(FXint incMode) {
907  FXdouble inc = incr[incMode + 1];
908  FXdouble newpos;
909  if (range[0] < range[1]) {
910  if (options & SPINDIAL_LOG) {
911  newpos = pos * inc;
912  if (options & SPINDIAL_CYCLIC && newpos > range[1]) {
913  // can have a huge magnitude disparity here, so better to work in log space
914  FXdouble lr0 = log(range[0]), lr1 = log(range[1]), lnp = log(newpos);
915  newpos = exp(lr0 + fmod(lnp - lr0, lr1 - lr0)) ;
916  }
917  } else {
918  newpos = pos + inc;
919  if (options & SPINDIAL_CYCLIC) {
920  newpos = range[0] + fmod(newpos - range[0], range[1] - range[0] + 1) ;
921  }
922  }
923  setValue(newpos);
924  }
925 }
926 
927 
928 // Decrement spinner
929 void FXRealSpinDial::decrement(FXint incMode) {
930  FXdouble inc = incr[incMode + 1];
931  FXdouble newpos;
932  if (range[0] < range[1]) {
933  if (options & SPINDIAL_LOG) {
934  newpos = pos / inc;
935  if (options & SPINDIAL_CYCLIC && newpos < range[0]) {
936  // can have a huge magnitude disparity here, so better to work in log space
937  FXdouble lr0 = log(range[0]), lr1 = log(range[1]), lpos = log(pos);
938  FXdouble span = lr1 - lr0;
939  newpos = exp(lr0 + fmod(lpos - lr0 + 1 + (span - inc), span));
940  }
941  } else {
942  newpos = pos - inc;
943  if (options & SPINDIAL_CYCLIC) {
944  newpos = range[0] + fmod(pos + (range[1] - range[0] + 1 + (newpos - pos) - range[0]) , range[1] - range[0] + 1);
945  }
946  }
947  setValue(newpos);
948  }
949 }
950 
951 // True if spinner is cyclic
952 FXbool FXRealSpinDial::isCyclic() const {
953  return (options & SPINDIAL_CYCLIC) != 0;
954 }
955 
956 
957 // Set spinner cyclic mode
958 void FXRealSpinDial::setCyclic(FXbool cyclic) {
959  if (cyclic) {
960  options |= SPINDIAL_CYCLIC;
961  } else {
962  options &= ~SPINDIAL_CYCLIC;
963  }
964 }
965 
966 
967 // Set spinner range; this also revalidates the position,
968 void FXRealSpinDial::setRange(FXdouble lo, FXdouble hi) {
969  if (lo > hi) {
970  fxerror("%s::setRange: trying to set negative range.\n", getClassName());
971  }
972  if (range[0] != lo || range[1] != hi) {
973  range[0] = lo;
974  range[1] = hi;
975  setValue(pos);
976  }
977 }
978 
979 
980 // Set new value
981 void FXRealSpinDial::setValue(FXdouble value) {
982  if (value < range[0]) {
983  value = range[0];
984  }
985  if (value > range[1]) {
986  value = range[1];
987  }
988  if (pos != value) {
989  textField->handle(this, FXSEL(SEL_COMMAND, ID_SETREALVALUE), &value);
990  pos = value;
991  }
992 }
993 
994 
995 // Change value increment
996 void FXRealSpinDial::setIncrement(FXdouble inc) {
997  if (inc < 0) {
998  fxerror("%s::setIncrement: negative or zero increment specified.\n", getClassName());
999  }
1000  incr[1] = inc;
1001 }
1003  if (inc < 0) {
1004  fxerror("%s::setIncrement: negative or zero increment specified.\n", getClassName());
1005  }
1006  incr[0] = inc;
1007 }
1009  if (inc < 0) {
1010  fxerror("%s::setIncrement: negative or zero increment specified.\n", getClassName());
1011  }
1012  incr[2] = inc;
1013 }
1014 void FXRealSpinDial::setIncrements(FXdouble fine, FXdouble inc, FXdouble coarse) {
1015  if (inc < 0) {
1016  fxerror("%s::setIncrement: negative or zero increment specified.\n", getClassName());
1017  }
1018  incr[0] = fine;
1019  incr[1] = inc;
1020  incr[2] = coarse;
1021 }
1022 
1023 
1024 // True if text supposed to be visible
1026  return textField->shown();
1027 }
1028 
1029 
1030 // Change text visibility
1032  FXuint opts = shown ? (options&~SPINDIAL_NOTEXT) : (options | SPINDIAL_NOTEXT);
1033  if (options != opts) {
1034  options = opts;
1035  recalc();
1036  }
1037 }
1038 
1039 
1040 // Set the font used in the text field|
1041 void FXRealSpinDial::setFont(FXFont* fnt) {
1042  textField->setFont(fnt);
1043 }
1044 
1045 
1046 // Return the font used in the text field
1047 FXFont* FXRealSpinDial::getFont() const {
1048  return textField->getFont();
1049 }
1050 
1051 
1052 // Set help text
1053 void FXRealSpinDial::setHelpText(const FXString& text) {
1054  textField->setHelpText(text);
1055  dial->setHelpText(text);
1056  upButton->setHelpText(text);
1057  downButton->setHelpText(text);
1058 }
1059 
1060 
1061 // Get help text
1063  return textField->getHelpText();
1064 }
1065 
1066 
1067 // Set tip text
1068 void FXRealSpinDial::setTipText(const FXString& text) {
1069  textField->setTipText(text);
1070  dial->setTipText(text);
1071  upButton->setTipText(text);
1072  downButton->setTipText(text);
1073 }
1074 
1075 
1076 
1077 // Get tip text
1078 FXString FXRealSpinDial::getTipText() const {
1079  return textField->getTipText();
1080 }
1081 
1082 
1083 // Change spinner style
1085  FXuint opts = (options&~SPINDIAL_MASK) | (style & SPINDIAL_MASK);
1086  if (options != opts) {
1087  if (opts & SPINDIAL_NOMIN) {
1088  range[0] = -DBL_MAX;
1089  }
1090  if (opts & SPINDIAL_NOMAX) {
1091  range[1] = DBL_MAX;
1092  }
1093  options = opts;
1094  recalc();
1095  }
1096 }
1097 
1098 
1099 // Get spinner style
1101  return (options & SPINDIAL_MASK);
1102 }
1103 
1104 
1105 // Allow editing of the text field
1106 void FXRealSpinDial::setEditable(FXbool edit) {
1107  textField->setEditable(edit);
1108 }
1109 
1110 
1111 // Return TRUE if text field is editable
1113  return textField->isEditable();
1114 }
1115 
1116 // Change color of the dial
1117 void FXRealSpinDial::setDialColor(FXColor clr) {
1118  dial->setBackColor(clr);
1119 }
1120 
1121 // Return color of the dial
1123  return dial->getBackColor();
1124 }
1125 
1126 // Change color of the up arrow
1128  upButton->setArrowColor(clr);
1129 }
1130 
1131 // Return color of the up arrow
1133  return upButton->getArrowColor();
1134 }
1135 
1136 // Change color of the down arrow
1138  downButton->setArrowColor(clr);
1139 }
1140 
1141 // Return color of the the down arrow
1143  return downButton->getArrowColor();
1144 }
1145 
1146 
1147 // Change text color
1148 void FXRealSpinDial::setTextColor(FXColor clr) {
1149  textField->setTextColor(clr);
1150 }
1151 
1152 // Return text color
1154  return textField->getTextColor();
1155 }
1156 
1157 // Change selected background color
1159  textField->setSelBackColor(clr);
1160 }
1161 
1162 // Return selected background color
1164  return textField->getSelBackColor();
1165 }
1166 
1167 // Change selected text color
1169  textField->setSelTextColor(clr);
1170 }
1171 
1172 // Return selected text color
1174  return textField->getSelTextColor();
1175 }
1176 
1177 // Changes the cursor color
1179  textField->setCursorColor(clr);
1180 }
1181 
1182 // Return the cursor color
1184  return textField->getCursorColor();
1185 }
1186 
1187 void FXRealSpinDial::setNumberFormat(FXint prec, FXbool bExp) {
1188  textField->setNumberFormat(prec, bExp);
1189 }
1190 
1193 }
1194 
1197 }
1198 
1199 void FXRealSpinDial::setFormatString(const FXchar* fmt) {
1200  textField->setFormatString(fmt);
1201 }
1202 
1204  return textField->getNumberFormatString();
1205 }
1206 
1207 // Save object to stream
1208 void FXRealSpinDial::save(FXStream& store) const {
1209  FXPacker::save(store);
1210  store << textField;
1211  store << dial;
1212  store << upButton;
1213  store << downButton;
1214  store << range[0] << range[1];
1215  store << incr[0] << incr[1] << incr[2];
1216  store << pos;
1217 }
1218 
1219 
1220 // Load object from stream
1221 void FXRealSpinDial::load(FXStream& store) {
1222  FXPacker::load(store);
1223  store >> textField;
1224  store >> dial;
1225  store >> upButton;
1226  store >> downButton;
1227  store >> range[0] >> range[1];
1228  store >> incr[0] >> incr[1] >> incr[2];
1229  store >> pos;
1230 }
1231 
1232 
1233 // Destruct spinner:- trash it!
1235  textField = (FXRealSpinDialText*) - 1L;
1236  dial = (FXDial*) - 1L;
1237  upButton = (FXRealSpinDialBtn*) - 1L;
1238  downButton = (FXRealSpinDialBtn*) - 1L;
1239 }
1240 
1241 }
1242 
1243 
1244 void
1245 FXRealSpinDial::selectAll() {
1246  textField->selectAll();
1247 }
1248 
1249 
1250 
1251 const FXDial&
1253  return *dial;
1254 }
1255 
1256