Eclipse SUMO - Simulation of Urban MObility
MFXTextFieldIcon.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2006-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 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 
25 
26 #include <utils/common/StdDefs.h>
27 #include "MFXTextFieldIcon.h"
28 
29 #include <fxkeys.h>
30 #include <FX88591Codec.h>
31 #include <FX88591Codec.h>
32 #include <FXCP1252Codec.h>
33 #include <FXUTF16Codec.h>
34 
35 
36 // ===========================================================================
37 // Macros
38 // ===========================================================================
39 
40 #define JUSTIFY_MASK (JUSTIFY_HZ_APART|JUSTIFY_VT_APART)
41 #define TEXTFIELD_MASK (TEXTFIELD_PASSWD|TEXTFIELD_INTEGER|TEXTFIELD_REAL|TEXTFIELD_READONLY|TEXTFIELD_ENTER_ONLY|TEXTFIELD_LIMITED|TEXTFIELD_OVERSTRIKE|TEXTFIELD_AUTOHIDE|TEXTFIELD_AUTOGRAY)
42 #define ICON_SPACING 4 // Spacing between icon and label (2 + 2)
43 #define ICON_SIZE 16
44 
45 // ===========================================================================
46 // FOX callback mapping
47 // ===========================================================================
48 
49 // Map
50 FXDEFMAP(MFXTextFieldIcon) MFXTextFieldIconMap[] = {
51  FXMAPFUNC(SEL_PAINT, 0, MFXTextFieldIcon::onPaint),
52  FXMAPFUNC(SEL_UPDATE, 0, MFXTextFieldIcon::onUpdate),
53  FXMAPFUNC(SEL_MOTION, 0, MFXTextFieldIcon::onMotion),
54  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, MFXTextFieldIcon::onLeftBtnPress),
55  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, MFXTextFieldIcon::onLeftBtnRelease),
56  FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, MFXTextFieldIcon::onMiddleBtnPress),
57  FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, MFXTextFieldIcon::onMiddleBtnRelease),
58  FXMAPFUNC(SEL_KEYPRESS, 0, MFXTextFieldIcon::onKeyPress),
59  FXMAPFUNC(SEL_KEYRELEASE, 0, MFXTextFieldIcon::onKeyRelease),
60  FXMAPFUNC(SEL_VERIFY, 0, MFXTextFieldIcon::onVerify),
61  FXMAPFUNC(SEL_SELECTION_LOST, 0, MFXTextFieldIcon::onSelectionLost),
62  FXMAPFUNC(SEL_SELECTION_GAINED, 0, MFXTextFieldIcon::onSelectionGained),
63  FXMAPFUNC(SEL_SELECTION_REQUEST, 0, MFXTextFieldIcon::onSelectionRequest),
64  FXMAPFUNC(SEL_CLIPBOARD_LOST, 0, MFXTextFieldIcon::onClipboardLost),
65  FXMAPFUNC(SEL_CLIPBOARD_GAINED, 0, MFXTextFieldIcon::onClipboardGained),
66  FXMAPFUNC(SEL_CLIPBOARD_REQUEST, 0, MFXTextFieldIcon::onClipboardRequest),
67  FXMAPFUNC(SEL_FOCUSIN, 0, MFXTextFieldIcon::onFocusIn),
68  FXMAPFUNC(SEL_FOCUSOUT, 0, MFXTextFieldIcon::onFocusOut),
69  FXMAPFUNC(SEL_FOCUS_SELF, 0, MFXTextFieldIcon::onFocusSelf),
70  FXMAPFUNC(SEL_QUERY_TIP, 0, MFXTextFieldIcon::onQueryTip),
71  FXMAPFUNC(SEL_QUERY_HELP, 0, MFXTextFieldIcon::onQueryHelp),
72  FXMAPFUNC(SEL_TIMEOUT, FXTextField::ID_BLINK, MFXTextFieldIcon::onBlink),
73  FXMAPFUNC(SEL_TIMEOUT, FXTextField::ID_AUTOSCROLL, MFXTextFieldIcon::onAutoScroll),
74  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_TOGGLE_EDITABLE, MFXTextFieldIcon::onUpdToggleEditable),
75  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_TOGGLE_OVERSTRIKE, MFXTextFieldIcon::onUpdToggleOverstrike),
76  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_CUT_SEL, MFXTextFieldIcon::onUpdHaveSelection),
77  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_COPY_SEL, MFXTextFieldIcon::onUpdHaveSelection),
78  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_PASTE_SEL, MFXTextFieldIcon::onUpdYes),
79  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_DELETE_SEL, MFXTextFieldIcon::onUpdHaveSelection),
80  FXMAPFUNC(SEL_UPDATE, FXTextField::ID_SELECT_ALL, MFXTextFieldIcon::onUpdSelectAll),
81  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETVALUE, MFXTextFieldIcon::onCmdSetValue),
82  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETINTVALUE, MFXTextFieldIcon::onCmdSetIntValue),
83  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETREALVALUE, MFXTextFieldIcon::onCmdSetRealValue),
84  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETSTRINGVALUE, MFXTextFieldIcon::onCmdSetStringValue),
85  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETINTVALUE, MFXTextFieldIcon::onCmdGetIntValue),
86  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETREALVALUE, MFXTextFieldIcon::onCmdGetRealValue),
87  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETSTRINGVALUE, MFXTextFieldIcon::onCmdGetStringValue),
88  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_HOME, MFXTextFieldIcon::onCmdCursorHome),
89  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_END, MFXTextFieldIcon::onCmdCursorEnd),
90  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_RIGHT, MFXTextFieldIcon::onCmdCursorRight),
91  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_LEFT, MFXTextFieldIcon::onCmdCursorLeft),
92  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_LEFT, MFXTextFieldIcon::onCmdCursorWordLeft),
93  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_RIGHT, MFXTextFieldIcon::onCmdCursorWordRight),
94  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_START, MFXTextFieldIcon::onCmdCursorWordStart),
95  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_END, MFXTextFieldIcon::onCmdCursorWordEnd),
96  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_MARK, MFXTextFieldIcon::onCmdMark),
97  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_EXTEND, MFXTextFieldIcon::onCmdExtend),
98  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SELECT_ALL, MFXTextFieldIcon::onCmdSelectAll),
99  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DESELECT_ALL, MFXTextFieldIcon::onCmdDeselectAll),
100  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_CUT_SEL, MFXTextFieldIcon::onCmdCutSel),
101  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_COPY_SEL, MFXTextFieldIcon::onCmdCopySel),
102  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_PASTE_SEL, MFXTextFieldIcon::onCmdPasteSel),
103  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_PASTE_MIDDLE, MFXTextFieldIcon::onCmdPasteMiddle),
104  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE_SEL, MFXTextFieldIcon::onCmdDeleteSel),
105  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE_ALL, MFXTextFieldIcon::onCmdDeleteAll),
106  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_OVERST_STRING, MFXTextFieldIcon::onCmdOverstString),
107  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_INSERT_STRING, MFXTextFieldIcon::onCmdInsertString),
108  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_BACKSPACE, MFXTextFieldIcon::onCmdBackspace),
109  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_DELETE, MFXTextFieldIcon::onCmdDelete),
110  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_TOGGLE_EDITABLE, MFXTextFieldIcon::onCmdToggleEditable),
111  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_TOGGLE_OVERSTRIKE, MFXTextFieldIcon::onCmdToggleOverstrike),
112  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETHELPSTRING, MFXTextFieldIcon::onCmdSetHelp),
113  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETHELPSTRING, MFXTextFieldIcon::onCmdGetHelp),
114  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_SETTIPSTRING, MFXTextFieldIcon::onCmdSetTip),
115  FXMAPFUNC(SEL_COMMAND, FXTextField::ID_GETTIPSTRING, MFXTextFieldIcon::onCmdGetTip),
116 };
117 
118 // Object implementation
119 FXIMPLEMENT(MFXTextFieldIcon, FXFrame, MFXTextFieldIconMap, ARRAYNUMBER(MFXTextFieldIconMap))
120 
121 // ===========================================================================
122 // member method definitions
123 // ===========================================================================
124 
125 MFXTextFieldIcon::MFXTextFieldIcon(FXComposite* p, FXint ncols, FXIcon* ic, FXObject* tgt, FXSelector sel,
126  FXuint opts, FXint x, FXint y, FXint w, FXint h, FXint pl, FXint pr, FXint pt, FXint pb) :
127  FXFrame(p, opts, x, y, w, h, pl, pr, pt, pb),
128  icon(ic) {
129  if (ncols < 0) {
130  ncols = 0;
131  }
132  flags |= FLAG_ENABLED;
133  target = tgt;
134  message = sel;
135  if (!(options & JUSTIFY_RIGHT)) {
136  options |= JUSTIFY_LEFT;
137  }
138  defaultCursor = getApp()->getDefaultCursor(DEF_TEXT_CURSOR);
139  dragCursor = getApp()->getDefaultCursor(DEF_TEXT_CURSOR);
140  font = getApp()->getNormalFont();
141  backColor = getApp()->getBackColor();
142  textColor = getApp()->getForeColor();
143  selbackColor = getApp()->getSelbackColor();
144  seltextColor = getApp()->getSelforeColor();
145  cursorColor = getApp()->getForeColor();
146  columns = ncols;
147 }
148 
149 
151  getApp()->removeTimeout(this, FXTextField::ID_BLINK);
152  getApp()->removeTimeout(this, ID_AUTOSCROLL);
153  font = (FXFont*) - 1L;
154 }
155 
156 
157 void
159  FXFrame::create();
160  if (!textType) {
161  textType = getApp()->registerDragType(textTypeName);
162  }
163  if (!utf8Type) {
164  utf8Type = getApp()->registerDragType(utf8TypeName);
165  }
166  if (!utf16Type) {
167  utf16Type = getApp()->registerDragType(utf16TypeName);
168  }
169  font->create();
170 }
171 
172 
173 void
175  if (!fnt) {
176  fxerror("%s::setFont: NULL font specified.\n", getClassName());
177  }
178  if (font != fnt) {
179  font = fnt;
180  recalc();
181  update();
182  }
183 }
184 
185 
186 void
188  if (!(flags & FLAG_ENABLED)) {
189  FXFrame::enable();
190  update();
191  }
192 }
193 
194 
195 void
197  if (flags & FLAG_ENABLED) {
198  FXFrame::disable();
199  update();
200  }
201 }
202 
203 
204 FXint
206  return padleft + padright + (border << 1) + columns * font->getTextWidth("8", 1);
207 }
208 
209 
210 
211 FXint
213  return padtop + padbottom + (border << 1) + font->getFontHeight();
214 }
215 
216 
217 long
218 MFXTextFieldIcon::onUpdate(FXObject* sender, FXSelector sel, void* ptr) {
219  if (!FXFrame::onUpdate(sender, sel, ptr)) {
220  if (options & TEXTFIELD_AUTOHIDE) {
221  if (shown()) {
222  hide();
223  recalc();
224  }
225  }
226  if (options & TEXTFIELD_AUTOGRAY) {
227  disable();
228  }
229  }
230  return 1;
231 }
232 
233 
234 long
235 MFXTextFieldIcon::onSelectionGained(FXObject* sender, FXSelector sel, void* ptr) {
236  FXFrame::onSelectionGained(sender, sel, ptr);
237  update();
238  return 1;
239 }
240 
241 
242 long
243 MFXTextFieldIcon::onSelectionLost(FXObject* sender, FXSelector sel, void* ptr) {
244  FXFrame::onSelectionLost(sender, sel, ptr);
245  update();
246  return 1;
247 }
248 
249 
250 long
251 MFXTextFieldIcon::onSelectionRequest(FXObject* sender, FXSelector sel, void* ptr) {
252  FXEvent* event = (FXEvent*)ptr;
253  FXString string;
254  FXuint start;
255  FXuint len;
256 
257  // Make sure
258  FXASSERT(0 <= anchor && anchor <= contents.length());
259  FXASSERT(0 <= cursor && cursor <= contents.length());
260 
261  // Perhaps the target wants to supply its own data for the selection
262  if (FXFrame::onSelectionRequest(sender, sel, ptr)) {
263  return 1;
264  }
265 
266  // Recognize the request?
267  if (event->target == stringType || event->target == textType || event->target == utf8Type || event->target == utf16Type) {
268 
269  // Figure selected bytes
270  if (anchor < cursor) {
271  start = anchor;
272  len = cursor - anchor;
273  } else {
274  start = cursor;
275  len = anchor - cursor;
276  }
277 
278  // Get selected fragment
279  string = contents.mid(start, len);
280 
281  // If password mode, replace by stars
282  if (options & TEXTFIELD_PASSWD) {
283  string.assign('*', string.count());
284  }
285 
286  // Return text of the selection as UTF-8
287  if (event->target == utf8Type) {
288  FXTRACE((100, "Request UTF8\n"));
289  setDNDData(FROM_SELECTION, event->target, string);
290  return 1;
291  }
292 
293  // Return text of the selection translated to 8859-1
294  if (event->target == stringType || event->target == textType) {
295  FX88591Codec ascii;
296  FXTRACE((100, "Request ASCII\n"));
297  setDNDData(FROM_SELECTION, event->target, ascii.utf2mb(string));
298  return 1;
299  }
300 
301  // Return text of the selection translated to UTF-16
302  if (event->target == utf16Type) {
303  FXUTF16LECodec unicode; // FIXME maybe other endianness for unix
304  FXTRACE((100, "Request UTF16\n"));
305  setDNDData(FROM_SELECTION, event->target, unicode.utf2mb(string));
306  return 1;
307  }
308  }
309  return 0;
310 }
311 
312 
313 long
314 MFXTextFieldIcon::onClipboardGained(FXObject* sender, FXSelector sel, void* ptr) {
315  FXFrame::onClipboardGained(sender, sel, ptr);
316  return 1;
317 }
318 
319 
320 long
321 MFXTextFieldIcon::onClipboardLost(FXObject* sender, FXSelector sel, void* ptr) {
322  FXFrame::onClipboardLost(sender, sel, ptr);
323  clipped.clear();
324  return 1;
325 }
326 
327 
328 
329 long
330 MFXTextFieldIcon::onClipboardRequest(FXObject* sender, FXSelector sel, void* ptr) {
331  FXEvent* event = (FXEvent*)ptr;
332  FXString string;
333 
334  // Perhaps the target wants to supply its own data for the clipboard
335  if (FXFrame::onClipboardRequest(sender, sel, ptr)) {
336  return 1;
337  }
338 
339  // Recognize the request?
340  if (event->target == stringType || event->target == textType || event->target == utf8Type || event->target == utf16Type) {
341 
342  // Get clipped string
343  string = clipped;
344 
345  // If password mode, replace by stars
346  if (options & TEXTFIELD_PASSWD) {
347  string.assign('*', string.count());
348  }
349 
350  // Return clipped text as as UTF-8
351  if (event->target == utf8Type) {
352  FXTRACE((100, "Request UTF8\n"));
353  setDNDData(FROM_CLIPBOARD, event->target, string);
354  return 1;
355  }
356 
357  // Return clipped text translated to 8859-1
358  if (event->target == stringType || event->target == textType) {
359  FX88591Codec ascii;
360  FXTRACE((100, "Request ASCII\n"));
361  setDNDData(FROM_CLIPBOARD, event->target, ascii.utf2mb(string));
362  return 1;
363  }
364 
365  // Return text of the selection translated to UTF-16
366  if (event->target == utf16Type) {
367  FXUTF16LECodec unicode; // FIXME maybe other endianness for unix
368  FXTRACE((100, "Request UTF16\n"));
369  setDNDData(FROM_CLIPBOARD, event->target, unicode.utf2mb(string));
370  return 1;
371  }
372  }
373  return 0;
374 }
375 
376 
377 long
378 MFXTextFieldIcon::onBlink(FXObject*, FXSelector, void*) {
379  drawCursor(flags ^ FLAG_CARET);
380  getApp()->addTimeout(this, FXTextField::ID_BLINK, getApp()->getBlinkSpeed());
381  return 0;
382 }
383 
384 
385 long
386 MFXTextFieldIcon::onFocusIn(FXObject* sender, FXSelector sel, void* ptr) {
387  FXFrame::onFocusIn(sender, sel, ptr);
388  if (isEditable()) {
389  getApp()->addTimeout(this, FXTextField::ID_BLINK, getApp()->getBlinkSpeed());
390  drawCursor(FLAG_CARET);
391  }
392  if (hasSelection()) {
393  update(border, border, width - (border << 1), height - (border << 1));
394  }
395  return 1;
396 }
397 
398 
399 long
400 MFXTextFieldIcon::onFocusOut(FXObject* sender, FXSelector sel, void* ptr) {
401  FXFrame::onFocusOut(sender, sel, ptr);
402  getApp()->removeTimeout(this, FXTextField::ID_BLINK);
403  drawCursor(0);
404  if (hasSelection()) {
405  update(border, border, width - (border << 1), height - (border << 1));
406  }
407  return 1;
408 }
409 
410 
411 long
412 MFXTextFieldIcon::onFocusSelf(FXObject* sender, FXSelector sel, void* ptr) {
413  if (FXFrame::onFocusSelf(sender, sel, ptr)) {
414  FXEvent* event = (FXEvent*)ptr;
415  if (event->type == SEL_KEYPRESS || event->type == SEL_KEYRELEASE) {
416  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_SELECT_ALL), NULL);
417  }
418  return 1;
419  }
420  return 0;
421 }
422 
423 
424 bool
426  return true;
427 }
428 
429 
430 void
432  FXFrame::setFocus();
433  setDefault(TRUE);
434  flags &= ~FLAG_UPDATE;
435  if (getApp()->hasInputMethod()) {
436  createComposeContext();
437  }
438 }
439 
440 
441 void
443  FXFrame::killFocus();
444  setDefault(MAYBE);
445  flags |= FLAG_UPDATE;
446  if (flags & FLAG_CHANGED) {
447  flags &= ~FLAG_CHANGED;
448  if (!(options & TEXTFIELD_ENTER_ONLY)) {
449  if (target) {
450  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
451  }
452  }
453  }
454  if (getApp()->hasInputMethod()) {
455  destroyComposeContext();
456  }
457 }
458 
459 
460 long
461 MFXTextFieldIcon::onCmdSetHelp(FXObject*, FXSelector, void* ptr) {
462  setHelpText(*((FXString*)ptr));
463  return 1;
464 }
465 
466 
467 long
468 MFXTextFieldIcon::onCmdGetHelp(FXObject*, FXSelector, void* ptr) {
469  *((FXString*)ptr) = getHelpText();
470  return 1;
471 }
472 
473 
474 long
475 MFXTextFieldIcon::onCmdSetTip(FXObject*, FXSelector, void* ptr) {
476  setTipText(*((FXString*)ptr));
477  return 1;
478 }
479 
480 
481 long
482 MFXTextFieldIcon::onCmdGetTip(FXObject*, FXSelector, void* ptr) {
483  *((FXString*)ptr) = getTipText();
484  return 1;
485 }
486 
487 
488 long
489 MFXTextFieldIcon::onQueryTip(FXObject* sender, FXSelector sel, void* ptr) {
490  if (FXWindow::onQueryTip(sender, sel, ptr)) {
491  return 1;
492  }
493  if ((flags & FLAG_TIP) && !tip.empty()) {
494  sender->handle(this, FXSEL(SEL_COMMAND, ID_SETSTRINGVALUE), (void*)&tip);
495  return 1;
496  }
497  return 0;
498 }
499 
500 
501 long
502 MFXTextFieldIcon::onQueryHelp(FXObject* sender, FXSelector sel, void* ptr) {
503  if (FXWindow::onQueryHelp(sender, sel, ptr)) {
504  return 1;
505  }
506  if ((flags & FLAG_HELP) && !help.empty()) {
507  sender->handle(this, FXSEL(SEL_COMMAND, ID_SETSTRINGVALUE), (void*)&help);
508  return 1;
509  }
510  return 0;
511 }
512 
513 
514 long
515 MFXTextFieldIcon::onCmdSetValue(FXObject*, FXSelector, void* ptr) {
516  setText((const FXchar*)ptr);
517  return 1;
518 }
519 
520 
521 long
522 MFXTextFieldIcon::onCmdSetIntValue(FXObject*, FXSelector, void* ptr) {
523  setText(FXStringVal(*((FXint*)ptr)));
524  return 1;
525 }
526 
527 
528 long
529 MFXTextFieldIcon::onCmdSetRealValue(FXObject*, FXSelector, void* ptr) {
530  setText(FXStringVal(*((FXdouble*)ptr)));
531  return 1;
532 }
533 
534 
535 long
536 MFXTextFieldIcon::onCmdSetStringValue(FXObject*, FXSelector, void* ptr) {
537  setText(*((FXString*)ptr));
538  return 1;
539 }
540 
541 
542 long
543 MFXTextFieldIcon::onCmdGetIntValue(FXObject*, FXSelector, void* ptr) {
544  *((FXint*)ptr) = FXIntVal(contents);
545  return 1;
546 }
547 
548 
549 long
550 MFXTextFieldIcon::onCmdGetRealValue(FXObject*, FXSelector, void* ptr) {
551  *((FXdouble*)ptr) = FXDoubleVal(contents);
552  return 1;
553 }
554 
555 
556 long
557 MFXTextFieldIcon::onCmdGetStringValue(FXObject*, FXSelector, void* ptr) {
558  *((FXString*)ptr) = getText();
559  return 1;
560 }
561 
562 
563 long
564 MFXTextFieldIcon::onLeftBtnPress(FXObject*, FXSelector, void* ptr) {
565  FXEvent* ev = (FXEvent*)ptr;
566  flags &= ~FLAG_TIP;
567  handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
568  if (isEnabled()) {
569  grab();
570  if (target && target->tryHandle(this, FXSEL(SEL_LEFTBUTTONPRESS, message), ptr)) {
571  return 1;
572  }
573  flags &= ~FLAG_UPDATE;
574  if (ev->click_count == 1) {
575  setCursorPos(index(ev->win_x));
576  if (ev->state & SHIFTMASK) {
578  } else {
579  killSelection();
581  }
583  flags |= FLAG_PRESSED;
584  } else {
585  setAnchorPos(0);
586  setCursorPos(contents.length());
587  extendSelection(contents.length());
589  }
590  return 1;
591  }
592  return 0;
593 }
594 
595 
596 long
597 MFXTextFieldIcon::onLeftBtnRelease(FXObject*, FXSelector, void* ptr) {
598  if (isEnabled()) {
599  ungrab();
600  flags &= ~FLAG_PRESSED;
601  if (target) {
602  target->tryHandle(this, FXSEL(SEL_LEFTBUTTONRELEASE, message), ptr);
603  }
604  return 1;
605  }
606  return 0;
607 }
608 
609 
610 long
611 MFXTextFieldIcon::onMiddleBtnPress(FXObject*, FXSelector, void* ptr) {
612  FXEvent* ev = (FXEvent*)ptr;
613  flags &= ~FLAG_TIP;
614  handle(this, FXSEL(SEL_FOCUS_SELF, 0), ptr);
615  if (isEnabled()) {
616  grab();
617  if (target && target->tryHandle(this, FXSEL(SEL_MIDDLEBUTTONPRESS, message), ptr)) {
618  return 1;
619  }
620  setCursorPos(index(ev->win_x));
623  update(border, border, width - (border << 1), height - (border << 1));
624  flags &= ~FLAG_UPDATE;
625  return 1;
626  }
627  return 0;
628 }
629 
630 
631 long
632 MFXTextFieldIcon::onMiddleBtnRelease(FXObject*, FXSelector, void* ptr) {
633  if (isEnabled()) {
634  ungrab();
635  if (target && target->tryHandle(this, FXSEL(SEL_MIDDLEBUTTONRELEASE, message), ptr)) {
636  return 1;
637  }
638  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_MIDDLE), NULL);
639  }
640  return 0;
641 }
642 
643 
644 long
645 MFXTextFieldIcon::onMotion(FXObject*, FXSelector, void* ptr) {
646  FXEvent* event = (FXEvent*)ptr;
647  FXint t;
648  if (flags & FLAG_PRESSED) {
649  if (event->win_x < (border + padleft) || (width - border - padright) < event->win_x) {
650  if (!getApp()->hasTimeout(this, ID_AUTOSCROLL)) {
651  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
652  }
653  } else {
654  getApp()->removeTimeout(this, ID_AUTOSCROLL);
655  t = index(event->win_x);
656  if (t != cursor) {
657  drawCursor(0);
658  cursor = t;
660  }
661  }
662  return 1;
663  }
664  return 0;
665 }
666 
667 
668 long
669 MFXTextFieldIcon::onAutoScroll(FXObject*, FXSelector, void* ptr) {
670  FXEvent* event = (FXEvent*)ptr;
671  if (flags & FLAG_PRESSED) {
672  FXint newcursor = cursor;
673  FXint ll = border + padleft;
674  FXint rr = width - border - padright;
675  FXint ww = rr - ll;
676  FXint tw;
677 
678  if (options & TEXTFIELD_PASSWD) {
679  tw = font->getTextWidth("*", 1) * contents.count();
680  } else {
681  tw = font->getTextWidth(contents.text(), contents.length());
682  }
683 
684  // Text right-aligned
685  if (options & JUSTIFY_RIGHT) {
686 
687  // Scroll left
688  if (event->win_x < ll) {
689  if (tw > ww) {
690  shift += ll - event->win_x;
691  if (ww > tw - shift) {
692  shift = tw - ww;
693  } else {
694  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
695  }
696  }
697  newcursor = index(ll);
698  }
699 
700  // Scroll right
701  if (rr < event->win_x) {
702  if (tw > ww) {
703  shift += rr - event->win_x;
704  if (shift <= 0) {
705  shift = 0;
706  } else {
707  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
708  }
709  }
710  newcursor = index(rr);
711  }
712  }
713 
714  // Text left-aligned
715  else if (options & JUSTIFY_LEFT) {
716 
717  // Scroll left
718  if (event->win_x < ll) {
719  if (tw > ww) {
720  shift += ll - event->win_x;
721  if (shift >= 0) {
722  shift = 0;
723  } else {
724  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
725  }
726  }
727  newcursor = index(ll);
728  }
729 
730  // Scroll right
731  if (rr < event->win_x) {
732  if (tw > ww) {
733  shift += rr - event->win_x;
734  if (shift + tw < ww) {
735  shift = ww - tw;
736  } else {
737  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
738  }
739  }
740  newcursor = index(rr);
741  }
742  } else {
743  // Text centered, Scroll left
744  if (event->win_x < ll) {
745  if (tw > ww) {
746  shift += ll - event->win_x;
747  if (shift > tw / 2 - ww / 2) {
748  shift = tw / 2 - ww / 2;
749  } else {
750  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
751  }
752  }
753  newcursor = index(ll);
754  }
755  // Scroll right
756  if (rr < event->win_x) {
757  if (tw > ww) {
758  shift += rr - event->win_x;
759  if (shift < (ww - ww / 2) - tw / 2) {
760  shift = (ww - ww / 2) - tw / 2;
761  } else {
762  getApp()->addTimeout(this, ID_AUTOSCROLL, getApp()->getScrollSpeed(), event);
763  }
764  }
765  newcursor = index(rr);
766  }
767  }
768  // Extend the selection
769  if (newcursor != cursor) {
770  drawCursor(0);
771  cursor = newcursor;
773  }
774  }
775  return 1;
776 }
777 
778 
779 long
780 MFXTextFieldIcon::onCmdToggleOverstrike(FXObject*, FXSelector, void*) {
782  return 1;
783 }
784 
785 
786 long
787 MFXTextFieldIcon::onUpdToggleOverstrike(FXObject* sender, FXSelector, void*) {
788  sender->handle(this, isOverstrike() ? FXSEL(SEL_COMMAND, ID_CHECK) : FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
789  sender->handle(this, FXSEL(SEL_COMMAND, ID_SHOW), NULL);
790  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
791  return 1;
792 }
793 
794 
795 long
796 MFXTextFieldIcon::onCmdToggleEditable(FXObject*, FXSelector, void*) {
798  return 1;
799 }
800 
801 
802 long
803 MFXTextFieldIcon::onUpdToggleEditable(FXObject* sender, FXSelector, void*) {
804  sender->handle(this, isEditable() ? FXSEL(SEL_COMMAND, ID_CHECK) : FXSEL(SEL_COMMAND, ID_UNCHECK), NULL);
805  sender->handle(this, FXSEL(SEL_COMMAND, ID_SHOW), NULL);
806  sender->handle(this, FXSEL(SEL_COMMAND, ID_ENABLE), NULL);
807  return 1;
808 }
809 
810 
811 long
812 MFXTextFieldIcon::onUpdHaveSelection(FXObject* sender, FXSelector, void* ptr) {
813  sender->handle(this, hasSelection() ? FXSEL(SEL_COMMAND, ID_ENABLE) : FXSEL(SEL_COMMAND, ID_DISABLE), ptr);
814  return 1;
815 }
816 
817 
818 long
819 MFXTextFieldIcon::onUpdSelectAll(FXObject* sender, FXSelector, void* ptr) {
820  sender->handle(this, contents.empty() ? FXSEL(SEL_COMMAND, ID_DISABLE) : FXSEL(SEL_COMMAND, ID_ENABLE), ptr);
821  return 1;
822 }
823 
824 
825 void
827  pos = contents.validate(FXCLAMP(0, pos, contents.length()));
828  if (cursor != pos) {
829  drawCursor(0);
830  cursor = pos;
831  if (isEditable() && hasFocus()) {
832  drawCursor(FLAG_CARET);
833  }
834  }
835 }
836 
837 
838 void
840  anchor = contents.validate(FXCLAMP(0, pos, contents.length()));
841 }
842 
843 
844 void
846  FXint cl, ch, xx, xlo, xhi;
847  if ((state ^ flags) & FLAG_CARET) {
848  if (xid) {
849  FXDCWindow dc(this);
850  FXASSERT(0 <= cursor && cursor <= contents.length());
851  FXASSERT(0 <= anchor && anchor <= contents.length());
852  xx = coord(cursor) - 1;
853  // add icon spacing
854  if (icon) {
855  xx += ICON_SPACING + ICON_SIZE;
856  }
857  // Clip rectangle around cursor
858  xlo = FXMAX(xx - 2, border);
859  xhi = FXMIN(xx + 3, width - border);
860  // Cursor can overhang padding but not borders
861  dc.setClipRectangle(xlo, border, xhi - xlo, height - (border << 1));
862  // Draw I beam
863  if (state & FLAG_CARET) {
864  // Draw I-beam
865  dc.setForeground(cursorColor);
866  dc.fillRectangle(xx, padtop + border, 1, height - padbottom - padtop - (border << 1));
867  dc.fillRectangle(xx - 2, padtop + border, 5, 1);
868  dc.fillRectangle(xx - 2, height - border - padbottom - 1, 5, 1);
869  } else {
870  // Erase I-beam, plus the text immediately surrounding it
871  dc.setForeground(backColor);
872  dc.fillRectangle(xx - 2, border, 5, height - (border << 1));
873  // Draw two characters before and after cursor
874  cl = ch = cursor;
875  if (0 < cl) {
876  cl = contents.dec(cl);
877  if (0 < cl) {
878  cl = contents.dec(cl);
879  }
880  }
881  if (ch < contents.length()) {
882  ch = contents.inc(ch);
883  if (ch < contents.length()) {
884  ch = contents.inc(ch);
885  }
886  }
887  drawTextRange(dc, cl, ch);
888  }
889  }
890  flags ^= FLAG_CARET;
891  }
892 }
893 
894 
895 void
897  FXint rr = width - border - padright;
898  FXint ll = border + padleft;
899  FXint ww = rr - ll;
900  FXint tw;
901  if (!xid) {
902  return;
903  }
904 
905  // Figure text width
906  if (options & TEXTFIELD_PASSWD) {
907  tw = font->getTextWidth("*", 1) * contents.count();
908  } else {
909  tw = font->getTextWidth(contents.text(), contents.length());
910  }
911 
912  // Constrain shift
913  if (options & JUSTIFY_RIGHT) {
914  if (ww >= tw) {
915  shift = 0;
916  } else if (shift < 0) {
917  shift = 0;
918  } else if (shift > tw - ww) {
919  shift = tw - ww;
920  }
921  } else if (options & JUSTIFY_LEFT) {
922  if (ww >= tw) {
923  shift = 0;
924  } else if (shift > 0) {
925  shift = 0;
926  } else if (shift < ww - tw) {
927  shift = ww - tw;
928  }
929  } else {
930  if (ww >= tw) {
931  shift = 0;
932  } else if (shift > tw / 2 - ww / 2) {
933  shift = tw / 2 - ww / 2;
934  } else if (shift < (ww - ww / 2) - tw / 2) {
935  shift = (ww - ww / 2) - tw / 2;
936  }
937  }
938 
939  // Keep cursor in the picture if resizing field
941 
942  // Always redraw
943  update();
944 
945  flags &= ~(FXuint)FLAG_DIRTY;
946 }
947 
948 
949 void
951  FXint rr = width - border - padright;
952  FXint ll = border + padleft;
953  FXint ww = rr - ll;
954  FXint oldshift = shift;
955  FXint xx;
956  if (!xid) {
957  return;
958  }
959  pos = contents.validate(FXCLAMP(0, pos, contents.length()));
960  if (options & JUSTIFY_RIGHT) {
961  if (options & TEXTFIELD_PASSWD) {
962  xx = font->getTextWidth("*", 1) * contents.count(pos, contents.length());
963  } else {
964  xx = font->getTextWidth(&contents[pos], contents.length() - pos);
965  }
966  if (shift - xx > 0) {
967  shift = xx;
968  } else if (shift - xx < -ww) {
969  shift = xx - ww;
970  }
971  } else if (options & JUSTIFY_LEFT) {
972  if (options & TEXTFIELD_PASSWD) {
973  xx = font->getTextWidth("*", 1) * contents.index(pos);
974  } else {
975  xx = font->getTextWidth(contents.text(), pos);
976  }
977  if (shift + xx < 0) {
978  shift = -xx;
979  } else if (shift + xx >= ww) {
980  shift = ww - xx;
981  }
982  } else {
983  if (options & TEXTFIELD_PASSWD) {
984  xx = font->getTextWidth("*", 1) * contents.index(pos) - (font->getTextWidth("*", 1) * contents.count()) / 2;
985  } else {
986  xx = font->getTextWidth(contents.text(), pos) - font->getTextWidth(contents.text(), contents.length()) / 2;
987  }
988  if (shift + ww / 2 + xx < 0) {
989  shift = -ww / 2 - xx;
990  } else if (shift + ww / 2 + xx >= ww) {
991  shift = ww - ww / 2 - xx;
992  }
993  }
994  if (shift != oldshift) {
995  update(border, border, width - (border << 1), height - (border << 1));
996  }
997 }
998 
999 
1000 FXint
1001 MFXTextFieldIcon::index(FXint x) const {
1002  FXint rr = width - border - padright;
1003  FXint ll = border + padleft;
1004  FXint mm = (ll + rr) / 2;
1005  FXint pos, xx, cw;
1006  if (options & TEXTFIELD_PASSWD) {
1007  cw = font->getTextWidth("*", 1);
1008  if (options & JUSTIFY_RIGHT) {
1009  xx = rr - cw * contents.count();
1010  } else if (options & JUSTIFY_LEFT) {
1011  xx = ll;
1012  } else {
1013  xx = mm - (cw * contents.count()) / 2;
1014  }
1015  xx += shift;
1016  pos = contents.offset((x - xx + (cw >> 1)) / cw);
1017  } else {
1018  if (options & JUSTIFY_RIGHT) {
1019  xx = rr - font->getTextWidth(contents.text(), contents.length());
1020  } else if (options & JUSTIFY_LEFT) {
1021  xx = ll;
1022  } else {
1023  xx = mm - font->getTextWidth(contents.text(), contents.length()) / 2;
1024  }
1025  xx += shift;
1026  for (pos = 0; pos < contents.length(); pos = contents.inc(pos)) {
1027  cw = font->getTextWidth(&contents[pos], contents.extent(pos));
1028  if (x < (xx + (cw >> 1))) {
1029  break;
1030  }
1031  xx += cw;
1032  }
1033  }
1034  if (pos < 0) {
1035  pos = 0;
1036  }
1037  if (pos > contents.length()) {
1038  pos = contents.length();
1039  }
1040  return pos;
1041 }
1042 
1043 
1044 FXint
1045 MFXTextFieldIcon::coord(FXint i) const {
1046  FXint rr = width - border - padright;
1047  FXint ll = border + padleft;
1048  FXint mm = (ll + rr) / 2;
1049  FXint pos;
1050  FXASSERT(0 <= i && i <= contents.length());
1051  if (options & JUSTIFY_RIGHT) {
1052  if (options & TEXTFIELD_PASSWD) {
1053  pos = rr - font->getTextWidth("*", 1) * (contents.count() - contents.index(i));
1054  } else {
1055  pos = rr - font->getTextWidth(&contents[i], contents.length() - i);
1056  }
1057  } else if (options & JUSTIFY_LEFT) {
1058  if (options & TEXTFIELD_PASSWD) {
1059  pos = ll + font->getTextWidth("*", 1) * contents.index(i);
1060  } else {
1061  pos = ll + font->getTextWidth(contents.text(), i);
1062  }
1063  } else {
1064  if (options & TEXTFIELD_PASSWD) {
1065  pos = mm + font->getTextWidth("*", 1) * contents.index(i) - (font->getTextWidth("*", 1) * contents.count()) / 2;
1066  } else {
1067  pos = mm + font->getTextWidth(contents.text(), i) - font->getTextWidth(contents.text(), contents.length()) / 2;
1068  }
1069  }
1070  return pos + shift;
1071 }
1072 
1073 
1074 FXbool
1076  if (0 <= pos && pos <= contents.length()) {
1077  FXint x = coord(contents.validate(pos));
1078  return border + padleft <= x && x <= width - border - padright;
1079  }
1080  return FALSE;
1081 }
1082 
1083 
1084 FXbool
1086  return hasSelection() && FXMIN(anchor, cursor) <= pos && pos <= FXMAX(anchor, cursor);
1087 }
1088 
1089 
1090 void
1091 MFXTextFieldIcon::drawTextFragment(FXDCWindow& dc, FXint x, FXint y, FXint fm, FXint to) {
1092  x += font->getTextWidth(contents.text(), fm);
1093  y += font->getFontAscent();
1094  dc.drawText(x, y, &contents[fm], to - fm);
1095 }
1096 
1097 
1098 void
1099 MFXTextFieldIcon::drawPWDTextFragment(FXDCWindow& dc, FXint x, FXint y, FXint fm, FXint to) {
1100  FXint cw = font->getTextWidth("*", 1);
1101  FXint i;
1102  y += font->getFontAscent();
1103  x += cw * contents.index(fm);
1104  for (i = fm; i < to; i = contents.inc(i), x += cw) {
1105  dc.drawText(x, y, "*", 1);
1106  }
1107 }
1108 
1109 
1110 // Draw range of text
1111 void MFXTextFieldIcon::drawTextRange(FXDCWindow& dc, FXint fm, FXint to) {
1112  FXint sx, ex, xx, yy, cw, hh, ww, si, ei, lx, rx, t;
1113  FXint rr = width - border - padright;
1114  FXint ll = border + padleft;
1115  FXint mm = (ll + rr) / 2;
1116  if (to <= fm) {
1117  return;
1118  }
1119  // set font
1120  dc.setFont(font);
1121  // Text color
1122  dc.setForeground(textColor);
1123  // Height
1124  hh = font->getFontHeight();
1125  // Text sticks to top of field
1126  if (options & JUSTIFY_TOP) {
1127  yy = padtop + border;
1128  } else if (options & JUSTIFY_BOTTOM) {
1129  // Text sticks to bottom of field
1130  yy = height - padbottom - border - hh;
1131  } else {
1132  // Text centered in y
1133  yy = border + padtop + (height - padbottom - padtop - (border << 1) - hh) / 2;
1134  }
1135  if (anchor < cursor) {
1136  si = anchor;
1137  ei = cursor;
1138  } else {
1139  si = cursor;
1140  ei = anchor;
1141  }
1142  // Password mode
1143  if (options & TEXTFIELD_PASSWD) {
1144  cw = font->getTextWidth("*", 1);
1145  ww = cw * contents.count();
1146  // Text sticks to right of field
1147  if (options & JUSTIFY_RIGHT) {
1148  xx = shift + rr - ww;
1149  } else if (options & JUSTIFY_LEFT) {
1150  // Text sticks on left of field
1151  xx = shift + ll;
1152  } else {
1153  // Text centered in field
1154  xx = shift + mm - ww / 2;
1155  }
1156  // check if add icon spacing
1157  if (icon) {
1158  xx += ICON_SPACING + ICON_SIZE;
1159  }
1160  // Reduce to avoid drawing excessive amounts of text
1161  lx = xx + cw * contents.index(fm);
1162  rx = xx + cw * contents.index(to);
1163  while (fm < to) {
1164  if (lx + cw >= 0) {
1165  break;
1166  }
1167  lx += cw;
1168  fm = contents.inc(fm);
1169  }
1170  while (fm < to) {
1171  if (rx - cw < width) {
1172  break;
1173  }
1174  rx -= cw;
1175  to = contents.dec(to);
1176  }
1177  // Adjust selected range
1178  if (si < fm) {
1179  si = fm;
1180  }
1181  if (ei > to) {
1182  ei = to;
1183  }
1184 
1185  // Nothing selected
1186  if (!hasSelection() || to <= si || ei <= fm) {
1187  drawPWDTextFragment(dc, xx, yy, fm, to);
1188  } else {
1189  // Stuff selected
1190  if (fm < si) {
1191  drawPWDTextFragment(dc, xx, yy, fm, si);
1192  } else {
1193  si = fm;
1194  }
1195  if (ei < to) {
1196  drawPWDTextFragment(dc, xx, yy, ei, to);
1197  } else {
1198  ei = to;
1199  }
1200  if (si < ei) {
1201  sx = xx + cw * contents.index(si);
1202  ex = xx + cw * contents.index(ei);
1203  if (hasFocus()) {
1204  dc.setForeground(selbackColor);
1205  dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
1206  dc.setForeground(seltextColor);
1207  drawPWDTextFragment(dc, xx, yy, si, ei);
1208  } else {
1209  dc.setForeground(baseColor);
1210  dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
1211  dc.setForeground(textColor);
1212  drawPWDTextFragment(dc, xx, yy, si, ei);
1213  }
1214  }
1215  }
1216  } else {
1217  // Normal mode
1218  ww = font->getTextWidth(contents.text(), contents.length());
1219  // Text sticks to right of field
1220  if (options & JUSTIFY_RIGHT) {
1221  xx = shift + rr - ww;
1222  } else if (options & JUSTIFY_LEFT) {
1223  // Text sticks on left of field
1224  xx = shift + ll;
1225  } else {
1226  // Text centered in field
1227  xx = shift + mm - ww / 2;
1228  }
1229  // check if add icon spacing
1230  if (icon) {
1231  xx += ICON_SPACING + ICON_SIZE;
1232  }
1233  // Reduce to avoid drawing excessive amounts of text
1234  lx = xx + font->getTextWidth(&contents[0], fm);
1235  rx = lx + font->getTextWidth(&contents[fm], to - fm);
1236  while (fm < to) {
1237  t = contents.inc(fm);
1238  cw = font->getTextWidth(&contents[fm], t - fm);
1239  if (lx + cw >= 0) {
1240  break;
1241  }
1242  lx += cw;
1243  fm = t;
1244  }
1245  while (fm < to) {
1246  t = contents.dec(to);
1247  cw = font->getTextWidth(&contents[t], to - t);
1248  if (rx - cw < width) {
1249  break;
1250  }
1251  rx -= cw;
1252  to = t;
1253  }
1254 
1255  // Adjust selected range
1256  if (si < fm) {
1257  si = fm;
1258  }
1259  if (ei > to) {
1260  ei = to;
1261  }
1262 
1263  // Nothing selected
1264  if (!hasSelection() || to <= si || ei <= fm) {
1265  drawTextFragment(dc, xx, yy, fm, to);
1266  } else {
1267  // Stuff selected
1268  if (fm < si) {
1269  drawTextFragment(dc, xx, yy, fm, si);
1270  } else {
1271  si = fm;
1272  }
1273  if (ei < to) {
1274  drawTextFragment(dc, xx, yy, ei, to);
1275  } else {
1276  ei = to;
1277  }
1278  if (si < ei) {
1279  sx = xx + font->getTextWidth(contents.text(), si);
1280  ex = xx + font->getTextWidth(contents.text(), ei);
1281  if (hasFocus()) {
1282  dc.setForeground(selbackColor);
1283  dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
1284  dc.setForeground(seltextColor);
1285  drawTextFragment(dc, xx, yy, si, ei);
1286  } else {
1287  dc.setForeground(baseColor);
1288  dc.fillRectangle(sx, padtop + border, ex - sx, height - padtop - padbottom - (border << 1));
1289  dc.setForeground(textColor);
1290  drawTextFragment(dc, xx, yy, si, ei);
1291  }
1292  }
1293  }
1294  }
1295 }
1296 
1297 
1298 long
1299 MFXTextFieldIcon::onPaint(FXObject*, FXSelector, void* ptr) {
1300  FXEvent* ev = (FXEvent*)ptr;
1301  FXDCWindow dc(this, ev);
1302  // Draw frame
1303  drawFrame(dc, 0, 0, width, height);
1304  // Gray background if disabled
1305  if (isEnabled()) {
1306  dc.setForeground(backColor);
1307  } else {
1308  dc.setForeground(baseColor);
1309  }
1310  // Draw background
1311  dc.fillRectangle(border, border, width - (border << 1), height - (border << 1));
1312  // Draw text, clipped against frame interior
1313  dc.setClipRectangle(border, border, width - (border << 1), height - (border << 1));
1314  drawTextRange(dc, 0, contents.length());
1315  // Draw caret
1316  if (flags & FLAG_CARET) {
1317  int xx = coord(cursor) - 1;
1318  // check if add icon spacing
1319  if (icon) {
1320  xx += ICON_SPACING + ICON_SIZE;
1321  }
1322  dc.setForeground(cursorColor);
1323  dc.fillRectangle(xx, padtop + border, 1, height - padbottom - padtop - (border << 1));
1324  dc.fillRectangle(xx - 2, padtop + border, 5, 1);
1325  dc.fillRectangle(xx - 2, height - border - padbottom - 1, 5, 1);
1326  }
1327  // draw icon
1328  if (icon) {
1329  dc.drawIcon(icon, ICON_SPACING / 2, border + padtop + (height - padbottom - padtop - (border << 1) - ICON_SIZE) / 2);
1330  }
1331  return 1;
1332 }
1333 
1334 
1335 long
1336 MFXTextFieldIcon::onCmdCursorHome(FXObject*, FXSelector, void*) {
1337  setCursorPos(0);
1339  return 1;
1340 }
1341 
1342 
1343 long
1344 MFXTextFieldIcon::onCmdCursorEnd(FXObject*, FXSelector, void*) {
1345  setCursorPos(contents.length());
1347  return 1;
1348 }
1349 
1350 
1351 long
1352 MFXTextFieldIcon::onCmdCursorRight(FXObject*, FXSelector, void*) {
1355  return 1;
1356 }
1357 
1358 
1359 
1360 long
1361 MFXTextFieldIcon::onCmdCursorLeft(FXObject*, FXSelector, void*) {
1364  return 1;
1365 }
1366 
1367 
1368 static FXbool
1369 isdelimiter(const FXchar* delimiters, FXwchar w) {
1370  return w < 128 && strchr(delimiters, w); // FIXME for w >= 128
1371 }
1372 
1373 
1374 FXint
1375 MFXTextFieldIcon::leftWord(FXint pos) const {
1376  FXint pp = pos, p;
1377 
1378  // Ensure input is valid
1379  FXASSERT(0 <= pos && pos <= contents.length());
1380 
1381  // Back up until space or delimiter
1382  while (0 <= (p = contents.dec(pp)) && !Unicode::isSpace(contents.wc(p)) && !isdelimiter(delimiters, contents.wc(p))) {
1383  pp = p;
1384  }
1385 
1386  // Back up over run of spaces
1387  while (0 <= (p = contents.dec(pp)) && Unicode::isSpace(contents.wc(p))) {
1388  pp = p;
1389  }
1390 
1391  // One more in case we didn't move
1392  if ((pos == pp) && 0 <= (p = contents.dec(pp))) {
1393  pp = p;
1394  }
1395 
1396  return pp;
1397 }
1398 
1399 
1400 FXint
1402  FXint pp = pos;
1403 
1404  // Ensure input is valid
1405  FXASSERT(0 <= pos && pos <= contents.length());
1406 
1407  // Advance until space or delimiter
1408  while (pp < contents.length() && !Unicode::isSpace(contents.wc(pp)) && !isdelimiter(delimiters, contents.wc(pp))) {
1409  pp = contents.inc(pp);
1410  }
1411 
1412  // Advance over run of spaces
1413  while (pp < contents.length() && Unicode::isSpace(contents.wc(pp))) {
1414  pp = contents.inc(pp);
1415  }
1416 
1417  // One more in case we didn't move
1418  if ((pos == pp) && pp < contents.length()) {
1419  pp = contents.inc(pp);
1420  }
1421 
1422  return pp;
1423 }
1424 
1425 
1426 FXint
1428  FXint p;
1429  FXASSERT(0 <= pos && pos <= contents.length());
1430  if (pos == contents.length() || Unicode::isSpace(contents.wc(pos))) {
1431  while (0 <= (p = contents.dec(pos)) && Unicode::isSpace(contents.wc(p))) {
1432  pos = p;
1433  }
1434  } else if (isdelimiter(delimiters, contents.wc(pos))) {
1435  while (0 <= (p = contents.dec(pos)) && isdelimiter(delimiters, contents.wc(p))) {
1436  pos = p;
1437  }
1438  } else {
1439  while (0 <= (p = contents.dec(pos)) && !isdelimiter(delimiters, contents.wc(p)) && !Unicode::isSpace(contents.wc(p))) {
1440  pos = p;
1441  }
1442  }
1443  return pos;
1444 }
1445 
1446 
1447 FXint
1448 MFXTextFieldIcon::wordEnd(FXint pos) const {
1449  FXASSERT(0 <= pos && pos <= contents.length());
1450  if (pos == contents.length() || Unicode::isSpace(contents.wc(pos))) {
1451  while (pos < contents.length() && Unicode::isSpace(contents.wc(pos))) {
1452  pos = contents.inc(pos);
1453  }
1454  } else if (isdelimiter(delimiters, contents.wc(pos))) {
1455  while (pos < contents.length() && isdelimiter(delimiters, contents.wc(pos))) {
1456  pos = contents.inc(pos);
1457  }
1458  } else {
1459  while (pos < contents.length() && !isdelimiter(delimiters, contents.wc(pos)) && !Unicode::isSpace(contents.wc(pos))) {
1460  pos = contents.inc(pos);
1461  }
1462  }
1463  return pos;
1464 }
1465 
1466 
1467 long
1468 MFXTextFieldIcon::onCmdCursorWordRight(FXObject*, FXSelector, void*) {
1471  return 1;
1472 }
1473 
1474 
1475 long
1476 MFXTextFieldIcon::onCmdCursorWordLeft(FXObject*, FXSelector, void*) {
1479  return 1;
1480 }
1481 
1482 
1483 long
1484 MFXTextFieldIcon::onCmdCursorWordStart(FXObject*, FXSelector, void*) {
1487  return 1;
1488 }
1489 
1490 
1491 long
1492 MFXTextFieldIcon::onCmdCursorWordEnd(FXObject*, FXSelector, void*) {
1495  return 1;
1496 }
1497 
1498 
1499 long
1500 MFXTextFieldIcon::onCmdMark(FXObject*, FXSelector, void*) {
1502  return 1;
1503 }
1504 
1505 
1506 long
1507 MFXTextFieldIcon::onCmdExtend(FXObject*, FXSelector, void*) {
1509  return 1;
1510 }
1511 
1512 
1513 long
1514 MFXTextFieldIcon::onCmdSelectAll(FXObject*, FXSelector, void*) {
1515  selectAll();
1517  return 1;
1518 }
1519 
1520 
1521 long
1522 MFXTextFieldIcon::onCmdDeselectAll(FXObject*, FXSelector, void*) {
1523  killSelection();
1524  return 1;
1525 }
1526 
1527 
1528 long
1529 MFXTextFieldIcon::onCmdCutSel(FXObject*, FXSelector, void*) {
1530  if (isEditable()) {
1531  if (hasSelection()) {
1532  FXDragType types[4];
1533  types[0] = stringType;
1534  types[1] = textType;
1535  types[2] = utf8Type;
1536  types[3] = utf16Type;
1537  if (acquireClipboard(types, 4)) {
1538  if (anchor < cursor) {
1539  clipped = contents.mid(anchor, cursor - anchor);
1540  } else {
1541  clipped = contents.mid(cursor, anchor - cursor);
1542  }
1543  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
1544  }
1545  }
1546  } else {
1547  getApp()->beep();
1548  }
1549  return 1;
1550 }
1551 
1552 
1553 long
1554 MFXTextFieldIcon::onCmdCopySel(FXObject*, FXSelector, void*) {
1555  if (hasSelection()) {
1556  FXDragType types[4];
1557  types[0] = stringType;
1558  types[1] = textType;
1559  types[2] = utf8Type;
1560  types[3] = utf16Type;
1561  if (acquireClipboard(types, 4)) {
1562  if (anchor < cursor) {
1563  clipped = contents.mid(anchor, cursor - anchor);
1564  } else {
1565  clipped = contents.mid(cursor, anchor - cursor);
1566  }
1567  }
1568  }
1569  return 1;
1570 }
1571 
1572 
1573 long
1574 MFXTextFieldIcon::onCmdPasteSel(FXObject*, FXSelector, void*) {
1575  if (isEditable()) {
1576  FXString string;
1577 
1578  // Delete existing selection
1579  if (hasSelection()) {
1580  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
1581  }
1582 
1583  // First, try UTF-8
1584  if (getDNDData(FROM_CLIPBOARD, utf8Type, string)) {
1585  FXTRACE((100, "Paste UTF8\n"));
1586  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)string.text());
1587  return 1;
1588  }
1589 
1590  // Next, try UTF-16
1591  if (getDNDData(FROM_CLIPBOARD, utf16Type, string)) {
1592  FXUTF16LECodec unicode; // FIXME maybe other endianness for unix
1593  FXTRACE((100, "Paste UTF16\n"));
1594  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)unicode.mb2utf(string).text());
1595  return 1;
1596  }
1597 
1598  // Next, try good old Latin-1
1599  if (getDNDData(FROM_CLIPBOARD, stringType, string)) {
1600  FX88591Codec ascii;
1601  FXTRACE((100, "Paste ASCII\n"));
1602  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)ascii.mb2utf(string).text());
1603  return 1;
1604  }
1605  } else {
1606  getApp()->beep();
1607  }
1608  return 1;
1609 }
1610 
1611 
1612 long
1613 MFXTextFieldIcon::onCmdPasteMiddle(FXObject*, FXSelector, void*) {
1614  if (isEditable()) {
1615  FXString string;
1616 
1617  // First, try UTF-8
1618  if (getDNDData(FROM_SELECTION, utf8Type, string)) {
1619  FXTRACE((100, "Paste UTF8\n"));
1620  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)string.text());
1621  return 1;
1622  }
1623 
1624  // Next, try UTF-16
1625  if (getDNDData(FROM_SELECTION, utf16Type, string)) {
1626  FXUTF16LECodec unicode; // FIXME maybe other endianness for unix
1627  FXTRACE((100, "Paste UTF16\n"));
1628  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)unicode.mb2utf(string).text());
1629  return 1;
1630  }
1631 
1632  // Finally, try good old 8859-1
1633  if (getDNDData(FROM_SELECTION, stringType, string)) {
1634  FX88591Codec ascii;
1635  FXTRACE((100, "Paste ASCII\n"));
1636  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)ascii.mb2utf(string).text());
1637  return 1;
1638  }
1639  } else {
1640  getApp()->beep();
1641  }
1642  return 1;
1643 }
1644 
1645 
1646 long
1647 MFXTextFieldIcon::onCmdDeleteSel(FXObject*, FXSelector, void*) {
1648  if (isEditable()) {
1649  if (!hasSelection()) {
1650  return 1;
1651  }
1652  FXint st = FXMIN(anchor, cursor);
1653  FXint en = FXMAX(anchor, cursor);
1654  setCursorPos(st);
1655  setAnchorPos(st);
1656  contents.erase(st, en - st);
1657  layout();
1658  makePositionVisible(st);
1659  killSelection();
1660  flags |= FLAG_CHANGED;
1661  if (target) {
1662  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1663  }
1664  } else {
1665  getApp()->beep();
1666  }
1667  return 1;
1668 }
1669 
1670 
1671 long
1672 MFXTextFieldIcon::onCmdDeleteAll(FXObject*, FXSelector, void*) {
1673  if (isEditable()) {
1674  setCursorPos(0);
1675  setAnchorPos(0);
1676  contents.clear();
1677  layout();
1679  killSelection();
1680  flags |= FLAG_CHANGED;
1681  if (target) {
1682  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1683  }
1684  } else {
1685  getApp()->beep();
1686  }
1687  return 1;
1688 }
1689 
1690 
1691 long
1692 MFXTextFieldIcon::onCmdOverstString(FXObject*, FXSelector, void* ptr) {
1693  if (isEditable()) {
1694  FXString tentative = contents;
1695  FXint len = (int)strlen((FXchar*)ptr);
1696  FXint reppos = cursor;
1697  FXint replen = len;
1698  if (hasSelection()) {
1699  reppos = FXMIN(anchor, cursor);
1700  replen = FXMAX(anchor, cursor) - reppos;
1701  }
1702  tentative.replace(reppos, replen, (FXchar*)ptr, len);
1703  if (handle(this, FXSEL(SEL_VERIFY, 0), (void*)tentative.text())) {
1704  getApp()->beep();
1705  return 1;
1706  }
1707  setCursorPos(reppos);
1708  setAnchorPos(reppos);
1709  contents = tentative;
1710  layout();
1711  setCursorPos(reppos + len);
1712  setAnchorPos(reppos + len);
1713  makePositionVisible(reppos + len);
1714  killSelection();
1715  update(border, border, width - (border << 1), height - (border << 1));
1716  flags |= FLAG_CHANGED;
1717  if (target) {
1718  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1719  }
1720  } else {
1721  getApp()->beep();
1722  }
1723  return 1;
1724 }
1725 
1726 
1727 long
1728 MFXTextFieldIcon::onCmdInsertString(FXObject*, FXSelector, void* ptr) {
1729  if (isEditable()) {
1730  FXString tentative = contents;
1731  FXint len = (int)strlen((FXchar*)ptr);
1732  FXint reppos = cursor;
1733  FXint replen = 0;
1734  if (hasSelection()) {
1735  reppos = FXMIN(anchor, cursor);
1736  replen = FXMAX(anchor, cursor) - reppos;
1737  }
1738  tentative.replace(reppos, replen, (FXchar*)ptr, len);
1739  if (handle(this, FXSEL(SEL_VERIFY, 0), (void*)tentative.text())) {
1740  getApp()->beep();
1741  return 1;
1742  }
1743  setCursorPos(reppos);
1744  setAnchorPos(reppos);
1745  contents = tentative;
1746  layout();
1747  setCursorPos(reppos + len);
1748  setAnchorPos(reppos + len);
1749  makePositionVisible(reppos + len);
1750  killSelection();
1751  update(border, border, width - (border << 1), height - (border << 1));
1752  flags |= FLAG_CHANGED;
1753  if (target) {
1754  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1755  }
1756  } else {
1757  getApp()->beep();
1758  }
1759  return 1;
1760 }
1761 
1762 
1763 
1764 long
1765 MFXTextFieldIcon::onCmdBackspace(FXObject*, FXSelector, void*) {
1766  if (isEditable() && 0 < cursor) {
1769  contents.erase(cursor, contents.extent(cursor));
1770  layout();
1772  update(border, border, width - (border << 1), height - (border << 1));
1773  flags |= FLAG_CHANGED;
1774  if (target) {
1775  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1776  }
1777  } else {
1778  getApp()->beep();
1779  }
1780  return 1;
1781 }
1782 
1783 
1784 long
1785 MFXTextFieldIcon::onCmdDelete(FXObject*, FXSelector, void*) {
1786  if (isEditable() && cursor < contents.length()) {
1787  contents.erase(cursor, contents.extent(cursor));
1788  layout();
1792  update(border, border, width - (border << 1), height - (border << 1));
1793  flags |= FLAG_CHANGED;
1794  if (target) {
1795  target->tryHandle(this, FXSEL(SEL_CHANGED, message), (void*)contents.text());
1796  }
1797  } else {
1798  getApp()->beep();
1799  }
1800  return 1;
1801 }
1802 
1803 
1804 long
1805 MFXTextFieldIcon::onVerify(FXObject*, FXSelector, void* ptr) {
1806  FXchar* p = (FXchar*)ptr;
1807 
1808  // Limit number of columns
1809  if (options & TEXTFIELD_LIMITED) {
1810  if ((FXint)wcslen(p) > columns) {
1811  return 1;
1812  }
1813  }
1814 
1815  // Integer input
1816  if (options & TEXTFIELD_INTEGER) {
1817  while (Ascii::isSpace(*p)) {
1818  p++;
1819  }
1820  if (*p == '-' || *p == '+') {
1821  p++;
1822  }
1823  while (Ascii::isDigit(*p)) {
1824  p++;
1825  }
1826  while (Ascii::isSpace(*p)) {
1827  p++;
1828  }
1829  if (*p != '\0') {
1830  return 1; // Objection!
1831  }
1832  }
1833 
1834  // Real input
1835  if (options & TEXTFIELD_REAL) {
1836  while (Ascii::isSpace(*p)) {
1837  p++;
1838  }
1839  if (*p == '-' || *p == '+') {
1840  p++;
1841  }
1842  while (Ascii::isDigit(*p)) {
1843  p++;
1844  }
1845  if (*p == '.') {
1846  p++;
1847  }
1848  while (Ascii::isDigit(*p)) {
1849  p++;
1850  }
1851  if (*p == 'E' || *p == 'e') {
1852  p++;
1853  if (*p == '-' || *p == '+') {
1854  p++;
1855  }
1856  while (Ascii::isDigit(*p)) {
1857  p++;
1858  }
1859  }
1860  while (Ascii::isSpace(*p)) {
1861  p++;
1862  }
1863  if (*p != '\0') {
1864  return 1; // Objection!
1865  }
1866  }
1867 
1868  // Target has chance to object to the proposed change
1869  if (target && target->tryHandle(this, FXSEL(SEL_VERIFY, message), ptr)) {
1870  return 1;
1871  }
1872 
1873  // No objections have been raised!
1874  return 0;
1875 }
1876 
1877 
1878 long
1879 MFXTextFieldIcon::onKeyPress(FXObject*, FXSelector, void* ptr) {
1880  FXEvent* event = (FXEvent*)ptr;
1881  flags &= ~FLAG_TIP;
1882  if (isEnabled()) {
1883  FXTRACE((200, "%s::onKeyPress keysym = 0x%04x state = %04x\n", getClassName(), event->code, event->state));
1884  if (target && target->tryHandle(this, FXSEL(SEL_KEYPRESS, message), ptr)) {
1885  return 1;
1886  }
1887  flags &= ~FLAG_UPDATE;
1888  switch (event->code) {
1889  case KEY_Right:
1890  case KEY_KP_Right:
1891  if (!(event->state & SHIFTMASK)) {
1892  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
1893  }
1894  if (event->state & CONTROLMASK) {
1895  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_RIGHT), NULL);
1896  } else {
1897  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_RIGHT), NULL);
1898  }
1899  if (event->state & SHIFTMASK) {
1900  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
1901  } else {
1902  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
1903  }
1904  return 1;
1905  case KEY_Left:
1906  case KEY_KP_Left:
1907  if (!(event->state & SHIFTMASK)) {
1908  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
1909  }
1910  if (event->state & CONTROLMASK) {
1911  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_WORD_LEFT), NULL);
1912  } else {
1913  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_LEFT), NULL);
1914  }
1915  if (event->state & SHIFTMASK) {
1916  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
1917  } else {
1918  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
1919  }
1920  return 1;
1921  case KEY_Home:
1922  case KEY_KP_Home:
1923  if (!(event->state & SHIFTMASK)) {
1924  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
1925  }
1926  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_HOME), NULL);
1927  if (event->state & SHIFTMASK) {
1928  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
1929  } else {
1930  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
1931  }
1932  return 1;
1933  case KEY_End:
1934  case KEY_KP_End:
1935  if (!(event->state & SHIFTMASK)) {
1936  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DESELECT_ALL), NULL);
1937  }
1938  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CURSOR_END), NULL);
1939  if (event->state & SHIFTMASK) {
1940  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_EXTEND), NULL);
1941  } else {
1942  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_MARK), NULL);
1943  }
1944  return 1;
1945  case KEY_Insert:
1946  case KEY_KP_Insert:
1947  if (event->state & CONTROLMASK) {
1948  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_COPY_SEL), NULL);
1949  } else if (event->state & SHIFTMASK) {
1950  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_SEL), NULL);
1951  } else {
1952  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_TOGGLE_OVERSTRIKE), NULL);
1953  }
1954  return 1;
1955  case KEY_Delete:
1956  case KEY_KP_Delete:
1957  if (hasSelection()) {
1958  if (event->state & SHIFTMASK) {
1959  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CUT_SEL), NULL);
1960  } else {
1961  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
1962  }
1963  } else {
1964  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE), NULL);
1965  }
1966  return 1;
1967  case KEY_BackSpace:
1968  if (hasSelection()) {
1969  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_DELETE_SEL), NULL);
1970  } else {
1971  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_BACKSPACE), NULL);
1972  }
1973  return 1;
1974  case KEY_Return:
1975  case KEY_KP_Enter:
1976  if (isEditable()) {
1977  flags |= FLAG_UPDATE;
1978  flags &= ~FLAG_CHANGED;
1979  if (target) {
1980  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
1981  }
1982  } else {
1983  getApp()->beep();
1984  }
1985  return 1;
1986  case KEY_a:
1987  if (!(event->state & CONTROLMASK)) {
1988  break;
1989  }
1990  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_SELECT_ALL), NULL);
1991  return 1;
1992  case KEY_x:
1993  if (!(event->state & CONTROLMASK)) {
1994  break;
1995  }
1996  FALLTHROUGH;
1997  case KEY_F20: // Sun Cut key
1998  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_CUT_SEL), NULL);
1999  return 1;
2000  case KEY_c:
2001  if (!(event->state & CONTROLMASK)) {
2002  break;
2003  }
2004  FALLTHROUGH;
2005  case KEY_F16: // Sun Copy key
2006  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_COPY_SEL), NULL);
2007  return 1;
2008  case KEY_v:
2009  if (!(event->state & CONTROLMASK)) {
2010  break;
2011  }
2012  FALLTHROUGH;
2013  case KEY_F18: // Sun Paste key
2014  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_PASTE_SEL), NULL);
2015  return 1;
2016  default:
2017  break;
2018  }
2019  if ((event->state & (CONTROLMASK | ALTMASK)) || ((FXuchar)event->text[0] < 32)) {
2020  return 0;
2021  }
2022  if (isOverstrike()) {
2023  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_OVERST_STRING), (void*)event->text.text());
2024  } else {
2025  handle(this, FXSEL(SEL_COMMAND, FXTextField::ID_INSERT_STRING), (void*)event->text.text());
2026  }
2027  return 1;
2028  }
2029  return 0;
2030 }
2031 
2032 
2033 long
2034 MFXTextFieldIcon::onKeyRelease(FXObject*, FXSelector, void* ptr) {
2035  FXEvent* event = (FXEvent*)ptr;
2036  if (isEnabled()) {
2037  FXTRACE((200, "%s::onKeyRelease keysym = 0x%04x state = %04x\n", getClassName(), ((FXEvent*)ptr)->code, ((FXEvent*)ptr)->state));
2038  if (target && target->tryHandle(this, FXSEL(SEL_KEYRELEASE, message), ptr)) {
2039  return 1;
2040  }
2041  switch (event->code) {
2042  case KEY_Right:
2043  case KEY_KP_Right:
2044  case KEY_Left:
2045  case KEY_KP_Left:
2046  case KEY_Home:
2047  case KEY_KP_Home:
2048  case KEY_End:
2049  case KEY_KP_End:
2050  case KEY_Insert:
2051  case KEY_KP_Insert:
2052  case KEY_Delete:
2053  case KEY_KP_Delete:
2054  case KEY_BackSpace:
2055  case KEY_Return:
2056  case KEY_F20: // Sun Cut key
2057  case KEY_F16: // Sun Copy key
2058  case KEY_F18: // Sun Paste key
2059  return 1;
2060  case KEY_a:
2061  case KEY_x:
2062  case KEY_c:
2063  case KEY_v:
2064  if (event->state & CONTROLMASK) {
2065  return 1;
2066  }
2067  FALLTHROUGH;
2068  default:
2069  if ((event->state & (CONTROLMASK | ALTMASK)) || ((FXuchar)event->text[0] < 32)) {
2070  return 0;
2071  }
2072  return 1;
2073  }
2074  }
2075  return 0;
2076 }
2077 
2078 
2079 FXbool
2081  if (hasSelection()) {
2082  releaseSelection();
2083  update(border, border, width - (border << 1), height - (border << 1));
2084  return TRUE;
2085  }
2086  return FALSE;
2087 }
2088 
2089 
2090 FXbool
2092  setAnchorPos(0);
2093  setCursorPos(contents.length());
2095  return TRUE;
2096 }
2097 
2098 
2099 FXbool
2100 MFXTextFieldIcon::setSelection(FXint pos, FXint len) {
2101  setAnchorPos(pos);
2102  setCursorPos(pos + len);
2104  return TRUE;
2105 }
2106 
2107 
2108 FXbool
2110  FXDragType types[4];
2111 
2112  // Validate position to start of character
2113  pos = contents.validate(FXCLAMP(0, pos, contents.length()));
2114 
2115  // Got a selection at all?
2116  if (anchor != pos) {
2117  types[0] = stringType;
2118  types[1] = textType;
2119  types[2] = utf8Type;
2120  types[3] = utf16Type;
2121  if (!hasSelection()) {
2122  acquireSelection(types, 4);
2123  }
2124  } else {
2125  if (hasSelection()) {
2126  releaseSelection();
2127  }
2128  }
2129 
2130  update(border, border, width - (border << 1), height - (border << 1));
2131  return TRUE;
2132 }
2133 
2134 
2135 
2136 void
2137 MFXTextFieldIcon::setText(const FXString& text, FXbool notify) {
2138  killSelection();
2139  if (contents != text) {
2140  contents = text;
2141  anchor = contents.length();
2142  cursor = contents.length();
2143  if (xid) {
2144  layout();
2145  }
2146  if (notify && target) {
2147  target->tryHandle(this, FXSEL(SEL_COMMAND, message), (void*)contents.text());
2148  }
2149  }
2150 }
2151 
2152 
2153 void
2155  killSelection();
2156  icon = ic;
2157  anchor = contents.length();
2158  cursor = contents.length();
2159  if (xid) {
2160  layout();
2161  }
2162 }
2163 
2164 
2165 void
2167  if (textColor != clr) {
2168  textColor = clr;
2169  update();
2170  }
2171 }
2172 
2173 
2174 
2175 void
2177  if (selbackColor != clr) {
2178  selbackColor = clr;
2179  update();
2180  }
2181 }
2182 
2183 
2184 void
2186  if (seltextColor != clr) {
2187  seltextColor = clr;
2188  update();
2189  }
2190 }
2191 
2192 
2193 
2194 void
2196  if (clr != cursorColor) {
2197  cursorColor = clr;
2198  update();
2199  }
2200 }
2201 
2202 
2203 
2204 void
2206  if (ncols < 0) {
2207  ncols = 0;
2208  }
2209  if (columns != ncols) {
2210  shift = 0;
2211  columns = ncols;
2212  layout(); // This may not be necessary!
2213  recalc();
2214  update();
2215  }
2216 }
2217 
2218 
2219 
2220 FXbool
2222  return (options & TEXTFIELD_READONLY) == 0;
2223 }
2224 
2225 
2226 
2227 void
2229  if (edit) {
2230  options &= ~TEXTFIELD_READONLY;
2231  } else {
2232  options |= TEXTFIELD_READONLY;
2233  }
2234 }
2235 
2236 
2237 
2238 FXbool
2240  return (options & TEXTFIELD_OVERSTRIKE) != 0;
2241 }
2242 
2243 
2244 
2245 void
2247  if (over) {
2248  options |= TEXTFIELD_OVERSTRIKE;
2249  } else {
2250  options &= ~TEXTFIELD_OVERSTRIKE;
2251  }
2252 }
2253 
2254 
2255 void
2257  FXuint opts = (options & ~TEXTFIELD_MASK) | (style & TEXTFIELD_MASK);
2258  if (options != opts) {
2259  shift = 0;
2260  options = opts;
2261  recalc();
2262  update();
2263  }
2264 }
2265 
2266 
2267 
2268 FXuint
2270  return (options & TEXTFIELD_MASK);
2271 }
2272 
2273 
2274 
2275 void
2277  FXuint opts = (options & ~JUSTIFY_MASK) | (style & JUSTIFY_MASK);
2278  if (options != opts) {
2279  shift = 0;
2280  options = opts;
2281  recalc();
2282  update();
2283  }
2284 }
2285 
2286 
2287 
2288 FXuint
2290  return (options & JUSTIFY_MASK);
2291 }
2292 
2293 
2294 
2295 void
2296 MFXTextFieldIcon::save(FXStream& store) const {
2297  FXFrame::save(store);
2298  store << contents;
2299  store << font;
2300  store << textColor;
2301  store << selbackColor;
2302  store << seltextColor;
2303  store << cursorColor;
2304  store << columns;
2305  store << help;
2306  store << tip;
2307 }
2308 
2309 
2310 
2311 void
2312 MFXTextFieldIcon::load(FXStream& store) {
2313  FXFrame::load(store);
2314  store >> contents;
2315  store >> font;
2316  store >> textColor;
2317  store >> selbackColor;
2318  store >> seltextColor;
2319  store >> cursorColor;
2320  store >> columns;
2321  store >> help;
2322  store >> tip;
2323 }
2324 
2325 
2327  flags |= FLAG_ENABLED;
2328  font = (FXFont*) - 1L;
2329 }
@ KEY_a
Definition: GUIShortcuts.h:43
@ KEY_c
Definition: GUIShortcuts.h:45
@ KEY_x
Definition: GUIShortcuts.h:66
@ KEY_v
Definition: GUIShortcuts.h:64
#define ICON_SPACING
static FXbool isdelimiter(const FXchar *delimiters, FXwchar w)
FXDEFMAP(MFXTextFieldIcon) MFXTextFieldIconMap[]
#define JUSTIFY_MASK
#define TEXTFIELD_MASK
#define ICON_SIZE
#define FALLTHROUGH
Definition: StdDefs.h:35
FXString clipped
Clipped text.
FXint cursor
Cursor position.
FXString contents
Edited text.
long onCmdOverstString(FXObject *, FXSelector, void *)
virtual void save(FXStream &store) const
Save text field to a stream.
virtual void disable()
Disable text field.
FXint coord(FXint i) const
coordinates
const FXchar * delimiters
Set of delimiters.
long onCmdSelectAll(FXObject *, FXSelector, void *)
long onCmdGetStringValue(FXObject *, FXSelector, void *)
void setCursorColor(FXColor clr)
Changes the cursor color.
void setSelTextColor(FXColor clr)
Change selected text color.
virtual void setFocus()
Move the focus to this window.
void setOverstrike(FXbool over=TRUE)
Set overstrike mode.
long onLeftBtnRelease(FXObject *, FXSelector, void *)
long onCmdGetRealValue(FXObject *, FXSelector, void *)
long onCmdGetHelp(FXObject *, FXSelector, void *)
long onBlink(FXObject *, FXSelector, void *)
long onCmdCursorHome(FXObject *, FXSelector, void *)
long onCmdCursorWordStart(FXObject *, FXSelector, void *)
long onKeyPress(FXObject *, FXSelector, void *)
long onFocusIn(FXObject *, FXSelector, void *)
virtual void killFocus()
Remove the focus from this window.
long onCmdSetTip(FXObject *, FXSelector, void *)
FXint wordStart(FXint pos) const
word start
long onCmdToggleOverstrike(FXObject *, FXSelector, void *)
void drawPWDTextFragment(FXDCWindow &dc, FXint x, FXint y, FXint fm, FXint to)
draw password text fragment
FXint columns
Number of columns visible.
virtual void enable()
Enable text field.
long onClipboardGained(FXObject *, FXSelector, void *)
long onLeftBtnPress(FXObject *, FXSelector, void *)
long onFocusOut(FXObject *, FXSelector, void *)
virtual FXint getDefaultWidth()
Return default width.
long onAutoScroll(FXObject *, FXSelector, void *)
FXFont * font
Text font.
MFXTextFieldIcon()
FOX need this.
FXint anchor
Anchor position.
void drawTextFragment(FXDCWindow &dc, FXint x, FXint y, FXint fm, FXint to)
draw text fragment
FXbool killSelection()
Unselect the text.
long onCmdPasteSel(FXObject *, FXSelector, void *)
long onQueryTip(FXObject *, FXSelector, void *)
FXColor selbackColor
Selected background color.
long onCmdCopySel(FXObject *, FXSelector, void *)
void makePositionVisible(FXint pos)
Scroll text to make the given position visible.
void setSelBackColor(FXColor clr)
Change selected background color.
FXColor textColor
Text color.
long onUpdToggleOverstrike(FXObject *, FXSelector, void *)
long onVerify(FXObject *, FXSelector, void *)
FXint leftWord(FXint pos) const
left word
const FXString & getHelpText() const
Get the status line help text for this label.
long onCmdCursorLeft(FXObject *, FXSelector, void *)
long onCmdExtend(FXObject *, FXSelector, void *)
void drawTextRange(FXDCWindow &dc, FXint fm, FXint to)
draw text range
FXbool setSelection(FXint pos, FXint len)
Select len characters starting at given position pos.
long onMiddleBtnRelease(FXObject *, FXSelector, void *)
long onCmdCursorWordEnd(FXObject *, FXSelector, void *)
void drawCursor(FXuint state)
draw cursor
FXString tip
Tooltip.
void setAnchorPos(FXint pos)
Change anchor position.
long onKeyRelease(FXObject *, FXSelector, void *)
long onSelectionRequest(FXObject *, FXSelector, void *ptr)
long onCmdDelete(FXObject *, FXSelector, void *)
long onCmdDeleteSel(FXObject *, FXSelector, void *)
long onClipboardLost(FXObject *, FXSelector, void *)
long onCmdSetRealValue(FXObject *, FXSelector, void *)
long onCmdCursorEnd(FXObject *, FXSelector, void *)
FXColor cursorColor
Color of the Cursor.
FXColor seltextColor
Selected text color.
virtual bool canFocus() const
Yes, text field may receive focus.
long onCmdSetValue(FXObject *, FXSelector, void *)
void setCursorPos(FXint pos)
Set cursor position.
virtual void load(FXStream &store)
Load text field from a stream.
void setFont(FXFont *fnt)
Set the text font.
long onUpdate(FXObject *, FXSelector, void *)
FXbool extendSelection(FXint pos)
Extend the selection from the anchor to the given position.
FXString getText() const
Get the text for this label.
long onUpdSelectAll(FXObject *, FXSelector, void *)
FXint index(FXint x) const
index
long onCmdPasteMiddle(FXObject *, FXSelector, void *)
long onCmdCursorWordLeft(FXObject *, FXSelector, void *)
FXString help
Help string.
void setEditable(FXbool edit=TRUE)
Set editable mode.
long onCmdSetStringValue(FXObject *, FXSelector, void *)
long onMotion(FXObject *, FXSelector, void *)
virtual FXint getDefaultHeight()
Return default height.
long onCmdCutSel(FXObject *, FXSelector, void *)
long onFocusSelf(FXObject *, FXSelector, void *)
void setJustify(FXuint mode)
Change text justification mode.
FXuint getTextStyle() const
Return text style.
virtual ~MFXTextFieldIcon()
Destructor.
long onSelectionGained(FXObject *, FXSelector, void *)
long onCmdDeselectAll(FXObject *, FXSelector, void *)
FXbool isPosVisible(FXint pos) const
Return TRUE if position is fully visible.
long onUpdToggleEditable(FXObject *, FXSelector, void *)
FXbool selectAll()
Select all text.
void setNumColumns(FXint cols)
Change the default width of the text field.
FXint rightWord(FXint pos) const
right word
long onCmdGetTip(FXObject *, FXSelector, void *)
long onClipboardRequest(FXObject *, FXSelector, void *)
void setTextColor(FXColor clr)
Change text color.
long onSelectionLost(FXObject *, FXSelector, void *)
const FXString & getTipText() const
Get the tool tip message for this text field.
long onCmdToggleEditable(FXObject *, FXSelector, void *)
long onCmdSetHelp(FXObject *, FXSelector, void *)
long onCmdInsertString(FXObject *, FXSelector, void *)
long onPaint(FXObject *, FXSelector, void *)
fox callbacks
long onCmdDeleteAll(FXObject *, FXSelector, void *)
long onUpdHaveSelection(FXObject *, FXSelector, void *)
void setHelpText(const FXString &text)
Set the status line help text for this label.
FXbool isEditable() const
Return TRUE if text field may be edited.
FXint shift
Shift amount.
long onQueryHelp(FXObject *, FXSelector, void *)
void setIcon(FXIcon *ic)
Change the icon.
long onCmdSetIntValue(FXObject *, FXSelector, void *)
void setTextStyle(FXuint style)
Change text style.
long onCmdCursorRight(FXObject *, FXSelector, void *)
void setTipText(const FXString &text)
Set the tool tip message for this text field.
FXint wordEnd(FXint pos) const
word end
long onMiddleBtnPress(FXObject *, FXSelector, void *)
virtual void create()
Create server-side resources.
virtual void layout()
Perform layout.
FXbool isPosSelected(FXint pos) const
Return TRUE if position pos is selected.
void setText(const FXString &text, FXbool notify=FALSE)
Change the text and move cursor to end.
long onCmdGetIntValue(FXObject *, FXSelector, void *)
long onCmdBackspace(FXObject *, FXSelector, void *)
FXbool isOverstrike() const
Return TRUE if overstrike mode in effect.
long onCmdCursorWordRight(FXObject *, FXSelector, void *)
FXuint getJustify() const
Return text justification mode.
long onCmdMark(FXObject *, FXSelector, void *)