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