1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file input.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao and Mark Overmars
24 * All rights reserved.
25 *
26 * XForms Class FL_INPUT
27 * handle normal user inputs and exchange data with other
28 * applications via the X Selection machnism.
29 *
30 * Data structure is grossly wrong and very inefficient.
31 * Need to complete overhaul this someday.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "include/forms.h"
39 #include "flinternal.h"
40 #include <string.h>
41 #include <sys/types.h>
42 #include <stdlib.h>
43 #include <ctype.h>
44 #include "private/pinput.h"
45 #include "private/flvasprintf.h"
46
47
48 enum {
49 COMPLETE = 0,
50 PARTIAL = 1,
51 VSLIDER = 2,
52 HSLIDER = 4
53 };
54
55
56 static void correct_topline( FLI_INPUT_SPEC *,
57 int * );
58
59 static void redraw_scrollbar( FL_OBJECT * );
60
61 static int make_line_visible( FL_OBJECT * obj,
62 int ypos );
63
64 static int make_char_visible( FL_OBJECT * obj,
65 int xpos );
66
67 static void copy_attributes( FL_OBJECT * dest,
68 const FL_OBJECT * src );
69
70 static int date_validator( FL_OBJECT *,
71 const char *,
72 const char *,
73 int );
74
75 static int int_validator( FL_OBJECT *,
76 const char *,
77 const char *,
78 int );
79
80 static int float_validator( FL_OBJECT *,
81 const char *,
82 const char *,
83 int );
84
85 static int xytopos( FLI_INPUT_SPEC * sp,
86 int xpos,
87 int ypos );
88
89 enum {
90 NORMAL_SELECT,
91 WORD_SELECT,
92 LINE_SELECT
93 };
94
95
96 static int Input_Mode = FL_NORMAL_INPUT_MODE;
97
98
99 /***************************************
100 ***************************************/
101
102 static void
get_margin(int btype,int bw,FL_Coord * xm,FL_Coord * ym)103 get_margin( int btype,
104 int bw,
105 FL_Coord * xm,
106 FL_Coord * ym )
107 {
108 if ( btype == FL_FLAT_BOX
109 || btype == FL_NO_BOX
110 || btype == FL_FRAME_BOX
111 || btype == FL_EMBOSSED_BOX )
112 {
113 *xm = bw + 1;
114 *ym = 0.7 * bw + 1;
115 }
116 else
117 {
118 *xm = 2 * bw + ( bw == 1 );
119 *ym = bw + 1 + ( bw == 1 );
120 }
121 }
122
123
124 /***************************************
125 * Checks the size of scrollbars and input field. No drawing is allowed
126 ***************************************/
127
128 static void
check_scrollbar_size(FL_OBJECT * obj)129 check_scrollbar_size( FL_OBJECT * obj )
130 {
131 FLI_INPUT_SPEC *sp = obj->spec;
132 FL_Coord xmargin,
133 ymargin;
134 int bw = FL_abs( obj->bw );
135 int delta;
136 int h_on = sp->h_on,
137 v_on = sp->v_on;
138 int max_pixels = sp->max_pixels;
139
140 /* The test for sp->vscroll and sp->hscroll being set is only for
141 fdesign which might change the object type of a normal input to
142 a multiline input without creating them */
143
144 if ( sp->input->type != FL_MULTILINE_INPUT
145 || ! ( sp->vscroll && sp->hscroll ) )
146 return;
147
148 /* Compute the real input box size */
149
150 sp->input->x = sp->dummy->x;
151 sp->input->y = sp->dummy->y;
152
153 get_margin( sp->input->boxtype, bw, &xmargin, &ymargin );
154 sp->charh = fl_get_char_height( sp->input->lstyle, sp->input->lsize, 0, 0 );
155
156 /* See how many lines would fit in */
157
158 sp->screenlines = ( sp->dummy->h - 2.0 * ymargin ) / sp->charh + 0.001;
159
160 sp->v_on = sp->v_pref == FL_ON
161 || ( sp->screenlines && sp->screenlines < sp->lines
162 && sp->v_pref != FL_OFF );
163
164 if ( sp->v_on )
165 {
166 sp->vw = sp->vw_def;
167 sp->vscroll->x = sp->input->x + sp->dummy->w - sp->vw;
168 sp->vscroll->y = sp->input->y;
169 sp->vscroll->w = sp->vw;
170 fli_set_object_visibility( sp->vscroll, FL_VISIBLE );
171 }
172 else
173 {
174 sp->vw = 0;
175 fli_set_object_visibility( sp->vscroll, FL_INVISIBLE );
176 }
177
178 sp->input->w = sp->dummy->w - sp->vw;
179
180 sp->h_on = sp->h_pref == FL_ON
181 || ( max_pixels > sp->w
182 && sp->h_pref != FL_OFF );
183
184 if ( sp->h_on )
185 {
186 sp->h_on = 1;
187 sp->hh = sp->hh_def;
188 sp->hscroll->x = sp->input->x;
189 sp->hscroll->y = sp->input->y + sp->dummy->h - sp->hh;
190 sp->hscroll->h = sp->hh;
191 fli_set_object_visibility( sp->hscroll, FL_VISIBLE );
192
193 if ( ( delta = max_pixels - sp->w ) > 0 )
194 {
195 sp->hsize = ( double ) sp->w / max_pixels;
196 sp->hval = ( double ) sp->xoffset / delta;
197 sp->hinc1 = 8.0 * sp->charh / delta;
198 sp->hinc2 = ( sp->charh - 2.0 ) / delta;
199 }
200 else
201 sp->hsize = 1.0;
202 }
203 else
204 {
205 sp->hh = 0;
206 fli_set_object_visibility( sp->hscroll, FL_INVISIBLE );
207 }
208
209 sp->input->h = sp->dummy->h - sp->hh;
210 sp->h = sp->input->h - 2 * ymargin;
211
212 sp->screenlines = ( double ) sp->h / sp->charh + 0.001;
213
214 if ( ! sp->v_on && sp->screenlines < sp->lines && sp->h_pref != FL_OFF )
215 {
216 sp->v_on = 1;
217 sp->vw = sp->vw_def;
218 sp->vscroll->x = sp->input->x + sp->dummy->w - sp->vw;
219 sp->vscroll->y = sp->input->y;
220 sp->vscroll->visible = 1;
221 sp->input->w = sp->dummy->w - sp->vw;
222 }
223
224 if ( sp->v_on && ( delta = sp->lines - sp->screenlines ) > 0 )
225 {
226 sp->vval = ( sp->topline - 1.0 ) / delta;
227 sp->vsize = ( double ) sp->screenlines / sp->lines;
228 sp->vinc1 = ( sp->screenlines - 0.99 ) / delta;
229 sp->vinc2 = 1.01 / delta;
230 }
231 else
232 sp->vsize = 1.0;
233
234 sp->hscroll->w = sp->input->w;
235 fli_notify_object( sp->hscroll, FL_RESIZED );
236 sp->vscroll->h = sp->input->h;
237 fli_notify_object( sp->vscroll, FL_RESIZED );
238 sp->w = sp->input->w - 2 * xmargin;
239
240 if ( h_on != sp->h_on || v_on != sp->v_on )
241 {
242 sp->attrib = 1;
243 sp->dead_area = ! ( sp->h_on ^ sp->v_on );
244 }
245 }
246
247
248 /***************************************
249 ***************************************/
250
251 static void
draw_input(FL_OBJECT * obj)252 draw_input( FL_OBJECT * obj )
253 {
254 FLI_INPUT_SPEC *sp = obj->spec;
255 FL_COLOR col;
256 FL_COLOR curscol = fli_dithered( fl_vmode ) ? FL_BLACK : sp->curscol;
257 FL_Coord xmargin,
258 ymargin;
259 int bw = FL_abs( obj->bw );
260 int cx,
261 cy;
262 int max_pixels,
263 max_pixels_line;
264 static char *saved;
265
266 get_margin( obj->boxtype, bw, &xmargin, &ymargin );
267 sp->w = sp->input->w - 2 * xmargin;
268 sp->h = sp->input->h - 2 * ymargin;
269
270 col = obj->focus ? obj->col2 : obj->col1;
271
272 if ( sp->drawtype == COMPLETE )
273 {
274 fl_draw_box( obj->boxtype, sp->input->x, sp->input->y,
275 sp->input->w, sp->input->h, col, obj->bw );
276 fl_draw_object_label_outside( obj );
277 }
278
279 if ( obj->type == FL_SECRET_INPUT )
280 {
281 saved = sp->str;
282 sp->str = fl_strdup( sp->str );
283 memset( sp->str, sp->field_char, strlen( saved ) );
284 }
285
286 cx = sp->input->x + xmargin;
287 cy = sp->input->y + ymargin;
288
289 fl_set_text_clipping( cx, cy, sp->w, sp->h );
290 fl_set_clipping( cx, cy, sp->w, sp->h );
291
292 max_pixels = fli_draw_string( obj->type == FL_MULTILINE_INPUT ?
293 FL_ALIGN_LEFT_TOP : FL_ALIGN_LEFT,
294 cx - sp->xoffset, /* Bounding box */
295 cy - sp->yoffset,
296 sp->w + sp->xoffset,
297 sp->h + sp->yoffset,
298 -1, /* Clipping is already set */
299 col, sp->textcol, curscol,
300 obj->lstyle, obj->lsize,
301 ( sp->cursor_visible
302 && obj->focus
303 && sp->beginrange >= sp->endrange ) ?
304 sp->position : -1,
305 sp->beginrange, sp->endrange,
306 sp->str, sp->drawtype != COMPLETE,
307 sp->topline,
308 sp->topline + sp->screenlines, 0 );
309
310 max_pixels_line = fli_get_max_pixels_line( ) + 1;
311 sp->charh = fl_get_char_height( obj->lstyle, obj->lsize, 0, 0 );
312
313 if ( max_pixels > sp->max_pixels
314 || ( sp->max_pixels_line >= sp->topline
315 && sp->max_pixels_line <= sp->topline + sp->screenlines ) )
316 {
317 sp->max_pixels = max_pixels;
318 sp->max_pixels_line = max_pixels_line;
319 }
320
321 fl_unset_clipping( );
322 fl_unset_text_clipping( );
323
324 if ( obj->type == FL_SECRET_INPUT )
325 {
326 fli_safe_free( sp->str );
327 sp->str = saved;
328 }
329
330 sp->drawtype = COMPLETE;
331 }
332
333
334 #define DELIM( c ) ( c == ' ' || c == ',' || c == '.' || c == '\n' )
335
336
337 /***************************************
338 * Figures out selection region of mouse, returns whether anything changed
339 ***************************************/
340
341 static int
handle_select(FL_Coord mx,FL_Coord my,FL_OBJECT * obj,int movement,int mode)342 handle_select( FL_Coord mx,
343 FL_Coord my,
344 FL_OBJECT * obj,
345 int movement,
346 int mode )
347 {
348 FLI_INPUT_SPEC *sp = obj->spec;
349 int thepos,
350 n,
351 dummy;
352 int oldpos = sp->position,
353 oldbeg = sp->beginrange,
354 oldend = sp->endrange;
355 int bw = FL_abs( obj->bw );
356 FL_Coord xmargin,
357 ymargin;
358
359 if ( obj->type == FL_HIDDEN_INPUT )
360 return 0;
361
362 /* Compute the mouse position in the string */
363
364 get_margin( obj->boxtype, bw, &xmargin, &ymargin );
365
366 thepos = fli_get_pos_in_string( obj->type == FL_MULTILINE_INPUT ?
367 FL_ALIGN_LEFT_TOP : FL_ALIGN_LEFT,
368 sp->input->x + xmargin - sp->xoffset,
369 sp->input->y + ymargin - sp->yoffset,
370 sp->w + sp->xoffset,
371 sp->h + sp->yoffset,
372 obj->lstyle, obj->lsize,
373 mx, my, sp->str,
374 &sp->xpos, &sp->ypos, &dummy );
375
376 if ( mode == WORD_SELECT )
377 {
378 #if defined USE_CLASSIC_EDITKEYS
379 if ( sp->str[ thepos ] == ' ' )
380 return 0;
381
382 for ( n = thepos; sp->str[ n ] && ! DELIM( sp->str[ n ] ); n++ )
383 /* empty */ ;
384 sp->endrange = n;
385
386 for ( n = thepos; n >= 0 && ! DELIM( sp->str[ n ] ); n-- )
387 /* empty */ ;
388
389 sp->beginrange = n + 1;
390 #else
391 if ( ! isalnum( ( unsigned char ) sp->str[ thepos ] )
392 && sp->str[ thepos ] != '_' )
393 {
394 for ( n = thepos;
395 sp->str[ n ]
396 && ! isalnum( ( unsigned char ) sp->str[ n ] )
397 && sp->str[ n ] != '_'
398 && sp->str[ n ] != '\n';
399 n++ )
400 /* empty */ ;
401 sp->endrange = n;
402
403 for ( n = thepos;
404 n
405 && ! isalnum( ( unsigned char ) sp->str[ n ] )
406 && sp->str[ n ] != '_'
407 && sp->str[ n ] != '\n';
408 n-- )
409 /* empty */ ;
410 if ( n > 0 )
411 ++n;
412 sp->beginrange = n;
413 }
414 else
415 {
416 for ( n = thepos;
417 sp->str[ n ]
418 && ( isalnum( ( unsigned char ) sp->str[ n ] )
419 || sp->str[ n ] == '_' );
420 n++ )
421 /* empty */ ;
422 sp->endrange = n;
423
424 for ( n = thepos;
425 n && ( isalnum( ( unsigned char ) sp->str[ n ] )
426 || sp->str[ n ] == '_' );
427 n-- )
428 /* empty */ ;
429 if ( n > 0 )
430 ++n;
431 sp->beginrange = n;
432 }
433 #endif
434 }
435 else if ( mode == LINE_SELECT )
436 {
437 for ( n = thepos; sp->str[ n ] && sp->str[ n ] != '\n'; n++ )
438 /* empty */ ;
439 sp->endrange = n;
440
441 for ( n = thepos; n >= 0 && sp->str[ n ] != '\n'; n-- )
442 /* empty */ ;
443 sp->beginrange = n + 1;
444 }
445 else
446 {
447 /* Adapt the range */
448
449 if ( movement )
450 {
451 fl_freeze_form( obj->form );
452 make_line_visible( obj, sp->ypos );
453 make_char_visible( obj, sp->xpos );
454 fl_unfreeze_form( obj->form );
455
456 if ( thepos < sp->position )
457 {
458 sp->endrange = sp->position;
459 sp->beginrange = thepos;
460 }
461 else
462 {
463 sp->beginrange = sp->position;
464 sp->endrange = thepos;
465 }
466 }
467 else
468 {
469 sp->position = sp->beginrange = thepos;
470 sp->endrange = -1;
471 }
472 }
473
474 if ( sp->beginrange == sp->endrange )
475 sp->endrange = -1;
476
477 if ( sp->beginrange < 0 )
478 sp->beginrange = 0;
479
480 return oldpos != sp->position
481 || oldbeg != sp->beginrange
482 || oldend != sp->endrange;
483 }
484
485
486 /***************************************
487 * This is not XCUTBUFFER. It is generated by ^K and can be
488 * recalled by ^Y
489 ***************************************/
490
491 #define MAXCBLEN 512
492 static char cutbuf[ MAXCBLEN ];
493
494
495 /***************************************
496 * Delete a single char. dir =1 for next, dir -1 for prev
497 ***************************************/
498
499 static void
delete_char(FLI_INPUT_SPEC * sp,int dir,int slen)500 delete_char( FLI_INPUT_SPEC * sp,
501 int dir,
502 int slen )
503 {
504 int i = sp->position - ( dir < 0 );
505
506 if ( sp->str[ i ] == '\n' )
507 {
508 sp->lines--;
509 sp->ypos -= dir < 0;
510 }
511
512 memmove( sp->str + i, sp->str + i + 1, slen - i );
513 sp->position -= dir < 0;
514 }
515
516
517 /***************************************
518 * Removes a piece of the string
519 ***************************************/
520
521 static void
delete_piece(FL_OBJECT * obj,int start,int end)522 delete_piece( FL_OBJECT * obj,
523 int start,
524 int end )
525 {
526 FLI_INPUT_SPEC *sp = obj->spec;
527
528 memmove( sp->str + start, sp->str + end + 1, strlen( sp->str + end ) );
529 sp->position = start;
530
531 /* This can be expensive TODO */
532
533 sp->lines = fl_get_input_numberoflines( obj );
534 fl_get_input_cursorpos( obj, &sp->xpos, &sp->ypos );
535 }
536
537
538 #define get_substring_width( o, b, e ) \
539 fl_get_string_width( ( o )->lstyle, ( o )->lsize, \
540 ( ( FLI_INPUT_SPEC * ) ( o )->spec )->str + ( b ), \
541 ( e ) - ( b ) )
542
543 #define IsRegular( k ) ( ( k ) == '\n' \
544 || ( key >= 32 && key <= 255 && key != 127 ) )
545
546
547 /***************************************
548 * Editing command. Need 4 bytes. Byte1 for normal ASCII, byte2 for
549 * special keysyms, such as PageUP etc. Byte 3 is used by Latin3 etc.
550 * Byte 4 will be used to indicate modifiers.
551 ***************************************/
552
553 static FL_EditKeymap kmap;
554
555 static int paste_it( FL_OBJECT *,
556 const unsigned char *,
557 int );
558
559 static void set_default_keymap( int );
560
561 #define set_to_eol( p ) while ( ( p ) < slen && sp->str[ p ] != '\n' ) ( p )++
562
563
564 /***************************************
565 * Cursor moved. No editing.
566 ***************************************/
567
568 static void
handle_movement(FL_OBJECT * obj,int key,int slen,int startpos,int kmask)569 handle_movement( FL_OBJECT * obj,
570 int key,
571 int slen,
572 int startpos,
573 int kmask )
574 {
575 FLI_INPUT_SPEC *sp = obj->spec;
576 int ready,
577 width,
578 i,
579 oldwidth,
580 tt;
581
582 if ( IsHome( key ) )
583 {
584 fl_set_input_topline( obj, 1 );
585 sp->position = 0;
586 sp->ypos = 1;
587 }
588 else if ( IsPageDown( key ) )
589 fl_set_input_topline( obj, sp->topline + sp->screenlines );
590 else if ( IsHalfPageDown( key ) )
591 fl_set_input_topline( obj, sp->topline + sp->screenlines / 2 );
592 else if ( Is1LineDown( key ) )
593 fl_set_input_topline( obj, sp->topline + 1 );
594 else if ( IsPageUp( key ) )
595 fl_set_input_topline( obj, sp->topline - sp->screenlines );
596 else if ( IsHalfPageUp( key ) )
597 fl_set_input_topline( obj, sp->topline - sp->screenlines / 2 );
598 else if ( Is1LineUp( key ) )
599 fl_set_input_topline( obj, sp->topline - 1 );
600 else if ( key == '\t' || key == '\f' )
601 /* empty */ ;
602 else if ( IsEnd( key ) )
603 {
604 fl_set_input_topline( obj, sp->lines );
605 sp->position = slen;
606 fl_get_input_cursorpos( obj, &sp->xpos, &sp->ypos );
607 }
608 else if ( IsLeft( key ) ) /* Left key */
609 {
610 if ( shiftkey_down( kmask ) )
611 sp->position = startpos;
612 else if ( sp->position > 0 )
613 sp->position--;
614
615 if ( sp->str[ sp->position ] == '\n' )
616 {
617 sp->ypos--;
618
619 /* Compute starting position of current line */
620
621 startpos = sp->position;
622 while ( startpos > 0 && sp->str[ startpos - 1 ] != '\n' )
623 startpos--;
624 }
625 }
626 else if ( IsRight( key ) || key == kmap.moveto_eol )
627 {
628 if ( shiftkey_down( kmask ) || key == kmap.moveto_eol )
629 set_to_eol( sp->position );
630 else if ( sp->position < slen )
631 {
632 if ( sp->str[ sp->position ] == '\n' )
633 {
634 sp->ypos++;
635 startpos = sp->position + 1;
636 }
637 sp->position++;
638 }
639 }
640 else if ( IsUp( key ) ) /* Up key */
641 {
642 if ( startpos != 0 )
643 {
644 width = get_substring_width( obj, startpos, sp->position );
645 i = startpos - 1;
646
647 while ( i > 0 && sp->str[ i - 1 ] != '\n' )
648 i--;
649
650 oldwidth = 0.0;
651 sp->position = i;
652
653 ready = sp->str[ sp->position ] == '\n';
654
655 while ( ! ready )
656 {
657 tt = get_substring_width( obj, i, sp->position + 1 );
658 ready = 0.5 * ( oldwidth + tt ) >= width;
659 oldwidth = tt;
660
661 if ( ! ready )
662 sp->position++;
663
664 if ( sp->str[ sp->position ] == '\n' )
665 ready = 1;
666 }
667
668 if ( --sp->ypos < 1 )
669 sp->ypos = 1;
670 }
671 }
672 else if ( IsDown( key ) ) /* Down key */
673 {
674 width = get_substring_width( obj, startpos, sp->position );
675 i = sp->position + 1;
676
677 while ( i < slen && sp->str[ i - 1 ] != '\n' )
678 i++;
679
680 if ( i < slen )
681 {
682 oldwidth = 0.0;
683 sp->position = i;
684 ready = sp->position == slen || sp->str[ sp->position ] == '\n';
685
686 while ( ! ready )
687 {
688 tt = get_substring_width( obj, i, sp->position + 1 );
689 ready = 0.5 * ( oldwidth + tt ) >= width;
690 oldwidth = tt;
691
692 if ( ! ready )
693 sp->position++;
694
695 if ( sp->position == slen || sp->str[ sp->position ] == '\n' )
696 ready = 1;
697 }
698 }
699 else
700 sp->position = slen;
701
702 if ( ++sp->ypos > sp->lines )
703 sp->ypos = sp->lines;
704 }
705 else if ( key == kmap.moveto_bol )
706 sp->position = startpos;
707 else if ( key == kmap.moveto_prev_word )
708 {
709 #if defined USE_CLASSIC_EDITKEYS
710 if ( sp->position > 0 )
711 sp->position--;
712
713 while ( sp->position > 0
714 && ( sp->str[ sp->position ] == ' '
715 || sp->str[ sp->position ] == '\n' ) )
716 {
717 if ( sp->str[ sp->position ] == '\n' )
718 sp->ypos--;
719
720 sp->position--;
721 }
722
723 while ( sp->position > 0
724 && sp->str[ sp->position ] != ' '
725 && sp->str[ sp->position ] != '\n' )
726 sp->position--;
727 #else
728 if ( sp->position > 0 )
729 sp->position--;
730
731 if ( ! isalnum( ( unsigned char ) sp->str[ sp->position ] )
732 && sp->str[ sp->position ] != '_' )
733 while ( sp->position > 0
734 && ! ( isalnum( ( unsigned char )
735 sp->str[ sp->position ] )
736 || sp->str[ sp->position ] == '_' ) )
737 --sp->position;
738 else
739 while ( sp->position > 0
740 && ( isalnum( ( unsigned char ) sp->str[ sp->position ] )
741 || sp->str[ sp->position ] == '_' ) )
742 --sp->position;
743 #endif
744
745 if ( sp->position > 0 )
746 sp->position++;
747 }
748 else if ( key == kmap.moveto_next_word )
749 {
750 i = sp->position;
751
752 #if defined USE_CLASSIC_EDITKEYS
753 while ( i < slen && ( sp->str[ i ] == ' ' || sp->str[ i ] == '\n' ) )
754 {
755 if ( sp->str[ i ] == '\n' )
756 sp->ypos++;
757 i++;
758 }
759
760 while ( i < slen && sp->str[ i ] != ' ' && sp->str[ i ] != '\n' )
761 i++;
762 #else
763 if ( ! isalnum( ( unsigned char ) sp->str[ i ] )
764 && sp->str[ i ] != '_' )
765 while ( i < slen
766 && ! isalnum( ( unsigned char ) sp->str[ i ] )
767 && sp->str[ i ] != '_' )
768 ++i;
769 else
770 while ( i < slen
771 && ( isalnum( ( unsigned char ) sp->str[ i ] )
772 || sp->str[ i ] == '_' ) )
773 ++i;
774 #endif
775 sp->position = i;
776 }
777 }
778
779
780 /***************************************
781 * Editing
782 ***************************************/
783
784 static int
handle_edit(FL_OBJECT * obj,int key,int slen)785 handle_edit( FL_OBJECT * obj,
786 int key,
787 int slen )
788 {
789 FLI_INPUT_SPEC *sp = obj->spec;
790 int ret = FL_RETURN_CHANGED,
791 i;
792
793 if ( key == kmap.del_prev_char || key == kmap.backspace )
794 {
795 if ( sp->endrange >= 0 )
796 delete_piece( obj, sp->beginrange, sp->endrange - 1 );
797 else if ( sp->position > 0 )
798 delete_char( sp, -1, slen );
799 else
800 ret = FL_RETURN_NONE;
801 }
802 else if ( key == kmap.del_next_char )
803 {
804 if ( sp->endrange >= 0 )
805 delete_piece( obj, sp->beginrange, sp->endrange - 1 );
806 else if ( sp->position < slen )
807 delete_char( sp, 1, slen );
808 else
809 ret = FL_RETURN_NONE;
810 }
811 else if ( key == kmap.del_next_word )
812 {
813 if ( obj->type == FL_SECRET_INPUT || ( i = sp->position ) == slen )
814 ret = FL_RETURN_NONE;
815 else
816 {
817 #if defined USE_CLASSIC_EDITKEYS
818 while ( i < slen
819 && ( sp->str[ i ] == ' ' || sp->str[ i ] == '\n' ) )
820 i++;
821 while ( i < slen && sp->str[ i ] != ' ' && sp->str[ i ] != '\n' )
822 i++;
823 #else
824 /* If the first character is neiter a letter nor a digit nor an
825 underscore delete it and all other characters of the same kind.
826 Otherwise delete all charaters that are letters. digit or
827 underscores. This is the same behaviour as in e.g. Qt.
828 */
829
830 if ( ! isalnum( ( unsigned char ) sp->str[ i ] )
831 && sp->str[ i ] != '_' )
832 while ( i < slen
833 && ! isalnum( ( unsigned char ) sp->str[ i ] )
834 && sp->str[ i ] != '_' )
835 i++;
836 else
837 while ( i < slen
838 && ( isalnum( ( unsigned char ) sp->str[ i ] )
839 || sp->str[ i ] == '_' ) )
840 i++;
841 #endif
842 if ( i - sp->position > 1 )
843 fli_sstrcpy( cutbuf, sp->str + sp->position,
844 FL_min( i - sp->position + 1, MAXCBLEN ) );
845
846 delete_piece( obj, sp->position, i - 1 );
847 }
848 }
849 else if ( key == kmap.del_prev_word )
850 {
851 int j = sp->position;
852
853 if ( obj->type == FL_SECRET_INPUT || j == 0 )
854 ret = FL_RETURN_NONE;
855 else
856 {
857
858 #if defined USE_CLASSIC_EDITKEYS
859 sp->position--;
860 while ( sp->position > 0
861 && ( sp->str[ sp->position ] == ' '
862 || sp->str[ sp->position ] == '\n' ) )
863 sp->position--;
864 while ( sp->position > 0
865 && sp->str[ sp->position ] != ' '
866 && sp->str[ sp->position ] != '\n' )
867 sp->position--;
868 #else
869 --sp->position;
870 if ( ! isalnum( ( unsigned char ) sp->str[ sp->position ] )
871 && sp->str[ sp->position ] != '_' )
872 while ( sp->position > 0
873 && ! isalnum( ( unsigned char )
874 sp->str[ sp->position ] )
875 && sp->str[ sp->position ] != '_' )
876 --sp->position;
877 else
878 while ( sp->position > 0
879 && ( isalnum( ( unsigned char )
880 sp->str[ sp->position ] )
881 || sp->str[ sp->position ] == '_' ) )
882 --sp->position;
883
884 if ( sp->position )
885 ++sp->position;
886 #endif
887 if ( sp->position != j )
888 {
889 if ( j - sp->position > 1 )
890 fli_sstrcpy( cutbuf, sp->str + sp->position,
891 FL_min( j - sp->position + 1, MAXCBLEN ) );
892 delete_piece( obj, sp->position, j - 1 );
893 }
894 else
895 ret = FL_RETURN_NONE;
896 }
897 }
898 else if ( key == kmap.clear_field )
899 {
900 if ( slen > 0 )
901 {
902 if ( slen > 1 )
903 fli_sstrcpy( cutbuf, sp->str, FL_min( slen, MAXCBLEN ) );
904 delete_piece( obj, 0, slen - 1 );
905 }
906 else
907 ret = FL_RETURN_NONE;
908 }
909 else if ( key == kmap.del_to_eol )
910 {
911 if ( slen > sp->position )
912 {
913 if ( sp->str[ sp->position ] != '\n' )
914 for ( i = sp->position; i < slen && sp->str[ i ] != '\n'; i++ )
915 /* empty */ ;
916 else
917 i = sp->position + 1;
918
919 /* Save buffer */
920
921 if ( i - sp->position > 1 )
922 fli_sstrcpy( cutbuf, sp->str + sp->position,
923 FL_min( i - sp->position + 1, MAXCBLEN ) );
924
925 delete_piece( obj, sp->position, i - 1 );
926 }
927 else
928 ret = FL_RETURN_NONE;
929 }
930 #if ! defined USE_CLASSIC_EDITKEYS
931 else if ( key == kmap.del_to_bol )
932 {
933 int j = sp->position;
934
935 if ( j == 0 )
936 ret = FL_RETURN_NONE;
937 else
938 {
939 if ( sp->str[ --sp->position ] != '\n' )
940 {
941 while ( sp->position > 0 && sp->str[ --sp->position ] != '\n' )
942 /* empty */;
943 if ( sp->str[ sp->position ] == '\n' )
944 ++sp->position;
945 }
946
947 if ( j - sp->position > 1 )
948 fli_sstrcpy( cutbuf, sp->str + sp->position,
949 FL_min( j - sp->position + 1, MAXCBLEN ) );
950
951 delete_piece( obj, sp->position, j - 1 );
952 }
953 }
954 #endif
955 else if ( key == kmap.paste )
956 paste_it( obj, ( unsigned char * ) cutbuf, strlen( cutbuf ) );
957 else if ( key == kmap.transpose && sp->position > 0 )
958 {
959 char t;
960
961 if ( sp->position < slen && sp->str[ sp->position ] != '\n' )
962 {
963 t = sp->str[ sp->position - 1 ];
964 sp->str[ sp->position - 1 ] = sp->str[ sp->position ];
965 sp->str[ sp->position ] = t;
966 sp->position++;
967 }
968 else
969 {
970 t = sp->str[ sp->position - 2 ];
971 sp->str[ sp->position - 2 ] = sp->str[ sp->position - 1 ];
972 sp->str[ sp->position - 1 ] = t;
973 }
974 }
975
976 return ret;
977 }
978
979
980 /***************************************
981 * Handles a key press, returns whether something has changed
982 ***************************************/
983
984 static int
handle_normal_key(FL_OBJECT * obj,int key,int slen)985 handle_normal_key( FL_OBJECT * obj,
986 int key,
987 int slen )
988 {
989 FLI_INPUT_SPEC *sp = obj->spec;
990 char *tmpbuf = NULL;
991 int tmppos = 0;
992 int ret = FL_RETURN_CHANGED;
993
994 /* Check that there's still room for a new character */
995
996 if ( sp->maxchars > 0
997 && slen >= sp->maxchars
998 && ( Input_Mode == FL_NORMAL_INPUT_MODE
999 || slen == sp->position ) )
1000 {
1001 fl_ringbell( 0 );
1002 return FL_RETURN_NONE;
1003 }
1004
1005 if ( sp->validate )
1006 {
1007 tmpbuf = fl_strdup( sp->str );
1008 tmppos = sp->position;
1009 }
1010
1011 /* If a range is marked remove it, it's replaced by the new character */
1012
1013 if ( sp->endrange >= 0 )
1014 {
1015 delete_piece( obj, sp->beginrange, sp->endrange - 1 );
1016 slen = strlen( sp->str );
1017 }
1018
1019 /* Merge the new character */
1020
1021 if ( Input_Mode == FL_DOS_INPUT_MODE
1022 && sp->maxchars > 0
1023 && slen == sp->maxchars )
1024 {
1025 memmove( sp->str + sp->position + 1, sp->str + sp->position,
1026 slen - sp->position );
1027 sp->str[ sp->maxchars ] = '\0';
1028 }
1029 else
1030 memmove( sp->str + sp->position + 1, sp->str + sp->position,
1031 slen - sp->position + 1 );
1032 sp->str[ sp->position++ ] = key;
1033
1034 if ( key == '\n' )
1035 {
1036 sp->lines++;
1037 sp->ypos++;
1038 }
1039
1040 if ( sp->validate )
1041 {
1042 int ok = sp->validate( obj, tmpbuf, sp->str, key );
1043
1044 if ( ( ok & ~ FL_RINGBELL ) != FL_VALID )
1045 {
1046 ret = FL_RETURN_NONE;
1047 strcpy( sp->str, tmpbuf );
1048 sp->position = tmppos;
1049
1050 if ( key == '\n' )
1051 {
1052 sp->lines--;
1053 sp->ypos--;
1054 }
1055 }
1056
1057 if ( ok & FL_RINGBELL )
1058 fl_ringbell( 0 );
1059 fl_free( tmpbuf );
1060 }
1061
1062 return ret;
1063 }
1064
1065
1066
1067 /***************************************
1068 * Handles a key press, returns whether the content of the input field
1069 * was changed
1070 ***************************************/
1071
1072 static int
handle_key(FL_OBJECT * obj,int key,unsigned int kmask)1073 handle_key( FL_OBJECT * obj,
1074 int key,
1075 unsigned int kmask )
1076 {
1077 int ret = FL_RETURN_NONE;
1078 FLI_INPUT_SPEC *sp = obj->spec;
1079 int slen; /* length of the string */
1080 int oldy = sp->ypos;
1081 int oldl = sp->lines;
1082 int oldx = sp->xoffset;
1083 int oldmax = sp->max_pixels;
1084
1085 /* Increase the size of the buffer for the text if it's full */
1086
1087 slen = strlen( sp->str );
1088
1089 if ( sp->size == slen + 1 )
1090 {
1091 sp->size += 8;
1092 sp->str = fl_realloc( sp->str, sp->size );
1093 }
1094
1095 /* Silently translate carriage return to line feed */
1096
1097 if ( obj->type == FL_MULTILINE_INPUT && key == '\r' )
1098 key = '\n';
1099
1100 #if defined USE_CLASSIC_EDITKEYS
1101 if ( controlkey_down( kmask ) && key > 255 )
1102 key |= FL_CONTROL_MASK;
1103 #else
1104 if ( controlkey_down( kmask ) )
1105 key |= FL_CONTROL_MASK;
1106 #endif
1107
1108 if ( metakey_down( kmask ) )
1109 key |= FL_ALT_MASK;
1110
1111 if ( shiftkey_down( kmask ) )
1112 {
1113 if ( key == XK_Up )
1114 key = XK_Home;
1115 else if ( key == XK_Down )
1116 key = XK_End;
1117 }
1118
1119 /* Translate all move keys to cursor keys so we can distinguish edit/move
1120 keys more easily */
1121
1122 if ( key == kmap.moveto_next_line )
1123 key = XK_Down;
1124 else if ( key == kmap.moveto_prev_line )
1125 key = XK_Up;
1126 else if ( key == kmap.moveto_prev_char )
1127 key = XK_Left;
1128 else if ( key == kmap.moveto_next_char )
1129 key = XK_Right;
1130 else if ( key == kmap.moveto_bof )
1131 key = XK_Home;
1132 else if ( key == kmap.moveto_eof )
1133 key = XK_End;
1134 else if ( key == kmap.moveto_next_page )
1135 key = XK_PageDn;
1136 else if ( key == kmap.moveto_prev_page )
1137 key = XK_PageUp;
1138
1139 if ( IsRegular( key ) ) /* Normal keys and new line */
1140 ret = handle_normal_key( obj, key, slen );
1141 else if ( IsCursorKey( key )
1142 || key == kmap.moveto_eol
1143 || key == kmap.moveto_bol
1144 || key == kmap.moveto_prev_word
1145 || key == kmap.moveto_next_word
1146 || Is1LineUp( key )
1147 || Is1LineDown( key )
1148 || IsHalfPageUp( key )
1149 || IsHalfPageDown( key ) )
1150 {
1151 int startpos = 0;
1152
1153 if ( obj->type == FL_MULTILINE_INPUT )
1154 {
1155 startpos = sp->position;
1156 while ( startpos > 0 && sp->str[ startpos - 1 ] != '\n' )
1157 startpos--;
1158 }
1159
1160 handle_movement( obj, key, slen, startpos, kmask );
1161
1162 if ( sp->endrange != -1 )
1163 {
1164 make_line_visible( obj, sp->ypos );
1165 make_char_visible( obj, sp->xpos );
1166 }
1167 }
1168 else
1169 ret = handle_edit( obj, key, slen );
1170
1171 sp->endrange = -1;
1172
1173 if ( ret != FL_RETURN_NONE )
1174 {
1175 int junk;
1176
1177 fl_get_string_dimension( obj->lstyle, obj->lsize, sp->str,
1178 strlen( sp->str ), &sp->max_pixels, &junk );
1179 }
1180
1181 if ( sp->noscroll )
1182 {
1183 sp->xoffset = sp->yoffset = 0;
1184 sp->topline = sp->ypos = 1;
1185 oldmax = sp->max_pixels;
1186 }
1187 else
1188 {
1189 int startpos = 0;
1190 int width;
1191
1192 if ( obj->type == FL_MULTILINE_INPUT )
1193 {
1194 startpos = sp->position;
1195 while ( startpos > 0 && sp->str[ startpos - 1 ] != '\n' )
1196 startpos--;
1197 }
1198
1199 width = fl_get_string_width( obj->lstyle, obj->lsize,
1200 sp->str + startpos,
1201 sp->position - startpos );
1202
1203 if ( width < sp->w - 4 )
1204 sp->xoffset = 0;
1205 else
1206 {
1207 if ( width - oldx > sp->w - 4 )
1208 sp->xoffset = width - sp->w + 4;
1209 else
1210 {
1211 int cw = fl_get_char_width( obj->lstyle, obj->lsize );
1212 if ( width - oldx < cw )
1213 sp->xoffset = width - cw;
1214 else
1215 sp->xoffset = oldx;
1216 }
1217 }
1218 }
1219
1220 fl_freeze_form( obj->form );
1221
1222 if ( oldl != sp->lines
1223 || oldy != sp->ypos
1224 || oldx != sp->xoffset
1225 || oldmax != sp->max_pixels )
1226 {
1227 check_scrollbar_size( obj );
1228 make_line_visible( obj, sp->ypos );
1229 redraw_scrollbar( obj );
1230 }
1231
1232 fl_redraw_object( sp->input );
1233 fl_unfreeze_form( obj->form );
1234
1235 return ret;
1236 }
1237
1238
1239 /***************************************
1240 * Given nb bytes of stuff, paste it into the input field.
1241 ***************************************/
1242
1243 static int
paste_it(FL_OBJECT * obj,const unsigned char * thebytes,int nb)1244 paste_it( FL_OBJECT * obj,
1245 const unsigned char * thebytes,
1246 int nb )
1247 {
1248 int ret = FL_RETURN_NONE;
1249
1250 while ( nb-- )
1251 ret |= handle_key( obj, *thebytes++, 0 );
1252
1253 return ret;
1254 }
1255
1256
1257 /***************************************
1258 * Callback for handling selection. It might be called only after
1259 * handling the input object is done and in that case we have to
1260 * insert the object into the onject queue manually...
1261 ***************************************/
1262
1263 /* handle X cut & paste ******************************* */
1264
1265 static int selection_hack = 0;
1266
1267 static int
gotit_cb(FL_OBJECT * obj,long type FL_UNUSED_ARG,const void * buf,long nb)1268 gotit_cb( FL_OBJECT * obj,
1269 long type FL_UNUSED_ARG,
1270 const void * buf,
1271 long nb )
1272 {
1273 FLI_INPUT_SPEC *sp = obj->spec;
1274
1275 sp->changed |= paste_it( obj, ( unsigned char * ) buf, nb );
1276 fl_update_display( 0 );
1277
1278 if ( selection_hack && sp->changed )
1279 {
1280 selection_hack = sp->changed = 0;
1281 obj->returned = FL_RETURN_CHANGED;
1282 fli_object_qenter( obj, FL_PASTE );
1283 }
1284
1285 return 0;
1286 }
1287
1288
1289 /***************************************
1290 * Paste request is handled here. If we do not own the selection,
1291 * this will result in an SelectionNotify event that gets handled
1292 * by handle_clipboard_event(). And in that case we can't report
1293 * the object to have changed back to the application since all
1294 * that will happen some time later. Thus we set 'selection_hack'
1295 * to indicate to the getit_cb() function to artificially enter
1296 * the object into the object queue.
1297 ***************************************/
1298
1299 static int
do_XPaste(FL_OBJECT * obj)1300 do_XPaste( FL_OBJECT * obj )
1301 {
1302 int ret = fl_request_clipboard( obj, XA_STRING, gotit_cb );
1303
1304 if ( ret == -1 && obj->how_return == FL_RETURN_CHANGED )
1305 selection_hack = 1;
1306 return ret > 0 ? FL_RETURN_CHANGED : FL_RETURN_NONE;
1307 }
1308
1309
1310 /***************************************
1311 ***************************************/
1312
1313 static int
lose_selection(FL_OBJECT * obj,long type FL_UNUSED_ARG)1314 lose_selection( FL_OBJECT * obj,
1315 long type FL_UNUSED_ARG )
1316 {
1317 FLI_INPUT_SPEC *sp = obj->spec;
1318
1319 sp->beginrange = sp->endrange = -1;
1320 if ( ! obj->focus )
1321 sp->position = -1;
1322 else if ( sp->position < 0 )
1323 sp->position = sp->str ? strlen( sp->str ) : 0;
1324 fl_redraw_object( sp->input );
1325 fl_update_display( 0 );
1326 return 0;
1327 }
1328
1329
1330 /***************************************
1331 ***************************************/
1332
1333 static void
do_XCut(FL_OBJECT * obj,int beginrange,int endrange)1334 do_XCut( FL_OBJECT * obj,
1335 int beginrange,
1336 int endrange )
1337 {
1338 FLI_INPUT_SPEC *sp = obj->spec;
1339 char *buff;
1340 int nc = endrange - beginrange + 1;
1341
1342 if ( nc <= 0 )
1343 return;
1344
1345 buff = fl_malloc( nc + 1 );
1346
1347 strncpy( buff, sp->str + beginrange, nc );
1348 buff[ nc ] = '\0';
1349
1350 fl_stuff_clipboard( obj, XA_STRING, buff, nc, lose_selection );
1351
1352 fl_free( buff );
1353 }
1354
1355
1356 /***************************************
1357 * Handles an event
1358 ***************************************/
1359
1360 static int
handle_input(FL_OBJECT * obj,int event,FL_Coord mx,FL_Coord my,int key,void * ev)1361 handle_input( FL_OBJECT * obj,
1362 int event,
1363 FL_Coord mx,
1364 FL_Coord my,
1365 int key,
1366 void * ev )
1367 {
1368 FLI_INPUT_SPEC *sp = obj->spec;
1369 static int motion,
1370 lx = INT_MAX,
1371 ly = INT_MAX,
1372 paste;
1373 int ret = FL_RETURN_NONE,
1374 val,
1375 state = 0;
1376
1377 /* Convert scroll wheel events to up or down arrow key events */
1378
1379 if ( event == FL_KEYPRESS )
1380 state = ( ( XKeyEvent * ) ev )->state;
1381
1382 if ( event == FL_PUSH )
1383 {
1384 if ( key == FL_MBUTTON4 )
1385 {
1386 event = FL_KEYPRESS;
1387 key = XK_Up;
1388 }
1389 else if ( key == FL_MBUTTON5 )
1390 {
1391 event = FL_KEYPRESS;
1392 key = XK_Down;
1393 }
1394 }
1395
1396 switch ( event )
1397 {
1398 case FL_ATTRIB :
1399 obj->align = fl_to_outside_lalign( obj->align );
1400 break;
1401
1402 case FL_RESIZED :
1403 check_scrollbar_size( obj );
1404 break;
1405
1406 case FL_DRAW:
1407 /* We always force label outside */
1408
1409 if ( sp->input->type != FL_MULTILINE_INPUT )
1410 {
1411 if ( sp->dummy != obj ) /* this can only happen with fdesign */
1412 sp->dummy = sp->input = obj;
1413 }
1414
1415 sp->dummy->align = fl_to_outside_lalign( sp->dummy->align );
1416 copy_attributes( sp->input, sp->dummy );
1417 if ( sp->input->type != FL_HIDDEN_INPUT )
1418 draw_input( sp->input );
1419 /* fall through */
1420
1421 case FL_DRAWLABEL:
1422 if ( sp->input->type != FL_MULTILINE_INPUT )
1423 fl_draw_object_label_outside( sp->input );
1424 else
1425 fl_draw_text_beside( sp->dummy->align,
1426 sp->input->x, sp->input->y,
1427 sp->input->w + sp->vw,
1428 sp->input->h + sp->hh,
1429 sp->input->lcol, sp->input->lstyle,
1430 sp->input->lsize, sp->dummy->label );
1431 break;
1432
1433 case FL_FOCUS:
1434 if ( obj->type == FL_MULTILINE_INPUT )
1435 {
1436 if ( sp->dummy->focus )
1437 break;
1438 sp->dummy->focus = 1;
1439 }
1440
1441 // Put the cursor back into the position where it was (except
1442 // for DOS mode where it's always positioned at the start)
1443
1444 if ( sp->str && Input_Mode != FL_DOS_INPUT_MODE )
1445 {
1446 if ( sp->position < 0 )
1447 sp->position = - sp->position - 1;
1448 if ( sp->position > ( int ) strlen( sp->str ) )
1449 sp->position = strlen( sp->str );
1450 }
1451 else
1452 sp->position = 0;
1453
1454 sp->changed = 0;
1455 fl_redraw_object( sp->input );
1456 break;
1457
1458 case FL_UNFOCUS:
1459 if ( obj->type == FL_MULTILINE_INPUT )
1460 sp->dummy->focus = 0;
1461
1462 if ( sp->position >= 0 )
1463 sp->position = - sp->position - 1;
1464 sp->endrange = -1;
1465 fl_redraw_object( sp->input );
1466
1467 /* If the event is set to NULL don't validate or report
1468 any changes - the call came from either closing the
1469 form or from the user changing the focus with the
1470 fl_set_focus_object() function - never use the event,
1471 it may be invalid */
1472
1473 if ( ev )
1474 ret = ( sp->changed ? FL_RETURN_CHANGED : FL_RETURN_NONE )
1475 | FL_RETURN_END;
1476
1477 break;
1478
1479 case FL_UPDATE:
1480 if ( ! obj->focus )
1481 break;
1482 motion = ( mx != lx || my != ly ) && ! paste;
1483 if ( motion && handle_select( mx, my, obj, 1, NORMAL_SELECT ) )
1484 fl_redraw_object( sp->input );
1485 break;
1486
1487 case FL_PUSH:
1488 paste = 0;
1489 lx = mx;
1490 ly = my;
1491 if ( key == FL_MBUTTON2 && ( sp->changed = do_XPaste( obj ) ) )
1492 {
1493 if ( obj->how_return == FL_RETURN_CHANGED )
1494 sp->changed = 0;
1495 ret = FL_RETURN_CHANGED;
1496 paste = 1;
1497 }
1498 else if ( handle_select( mx, my, obj, 0, NORMAL_SELECT ) )
1499 fl_redraw_object( sp->input );
1500 break;
1501
1502 case FL_RELEASE:
1503 if ( key == FL_MBUTTON4 || key == FL_MBUTTON5 )
1504 break;
1505 if ( key == FL_MBUTTON1 && motion )
1506 do_XCut( obj, sp->beginrange, sp->endrange - 1 );
1507 motion = 0;
1508 break;
1509
1510 case FL_DBLCLICK:
1511 case FL_TRPLCLICK:
1512 if ( key == FL_MBUTTON4 || key == FL_MBUTTON5 )
1513 break;
1514 if ( handle_select( mx, my, obj, 0,
1515 event == FL_DBLCLICK ?
1516 WORD_SELECT : LINE_SELECT ) )
1517 {
1518 fl_redraw_object( sp->input );
1519 do_XCut( obj, sp->beginrange, sp->endrange );
1520 }
1521 break;
1522
1523 case FL_KEYPRESS :
1524 if ( ( ret = handle_key( obj, key, state ) ) )
1525 {
1526 sp->changed = 1;
1527 if ( obj->how_return == FL_RETURN_CHANGED )
1528 sp->changed = 0;
1529 }
1530 break;
1531
1532 case FL_FREEMEM:
1533 fli_safe_free( ( ( FLI_INPUT_SPEC * ) obj->spec )->str );
1534 fli_safe_free( obj->spec );
1535 return ret;
1536 }
1537
1538 if ( ret
1539 && sp
1540 && sp->validate
1541 && event == FL_UNFOCUS
1542 && ( val = sp->validate( obj, sp->str, sp->str, 0 ) ) != FL_VALID )
1543 {
1544 ret = FL_RETURN_NONE;
1545 if ( val & FL_RINGBELL )
1546 {
1547 fl_ringbell( 0 );
1548 fl_reset_focus_object( obj );
1549 }
1550 }
1551
1552 /* In some places the x- and y-coordinates (column and row) of the cursor
1553 aren't set consistently, so repair it here... */
1554
1555 if ( obj->spec )
1556 fl_get_input_cursorpos( obj, &sp->xpos, &sp->ypos );
1557
1558 return ret;
1559 }
1560
1561
1562 /***************************************
1563 * Callback for the vertical scrollbar of multi-line input objects
1564 ***************************************/
1565
1566 static void
vsl_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)1567 vsl_cb( FL_OBJECT * obj,
1568 long data FL_UNUSED_ARG )
1569 {
1570 FLI_INPUT_SPEC *sp = obj->parent->spec;
1571
1572 double val = fl_get_scrollbar_value( obj );
1573 int top = FL_nint( val * ( sp->lines - sp->screenlines ) ) + 1;
1574
1575 sp->endrange = -1; /* switch off selection */
1576 sp->drawtype = VSLIDER;
1577 fl_set_input_topline( sp->input, top );
1578 }
1579
1580
1581 /***************************************
1582 * Callback for the horizontal scrollbar of multi-line input objects
1583 ***************************************/
1584
1585 static void
hsl_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)1586 hsl_cb( FL_OBJECT * obj,
1587 long data FL_UNUSED_ARG )
1588 {
1589 FLI_INPUT_SPEC *sp = obj->parent->spec;
1590 double val = fl_get_scrollbar_value( obj );
1591 int xoff = val * ( sp->max_pixels - sp->w ) + 0.1;
1592
1593 sp->drawtype = HSLIDER;
1594 fl_set_input_xoffset( sp->input, xoff );
1595 }
1596
1597
1598 /***************************************
1599 * Pre- and post- handlers
1600 ***************************************/
1601
1602 static int
input_pre(FL_OBJECT * obj,int ev,FL_Coord mx,FL_Coord my,int key,void * xev)1603 input_pre( FL_OBJECT * obj,
1604 int ev,
1605 FL_Coord mx,
1606 FL_Coord my,
1607 int key,
1608 void * xev )
1609 {
1610 FL_OBJECT *ext = obj->parent;
1611
1612 return ( ext && ext->prehandle ) ?
1613 ext->prehandle( ext, ev, mx, my, key, xev ) : 0;
1614 }
1615
1616
1617 /***************************************
1618 ***************************************/
1619
1620 static int
input_post(FL_OBJECT * obj,int ev,FL_Coord mx,FL_Coord my,int key,void * xev)1621 input_post( FL_OBJECT * obj,
1622 int ev,
1623 FL_Coord mx,
1624 FL_Coord my,
1625 int key,
1626 void * xev )
1627 {
1628 FL_OBJECT *ext = obj->parent;
1629
1630 return ( ext && ext->posthandle ) ?
1631 ext->posthandle( ext, ev, mx, my, key, xev ) : 0;
1632 }
1633
1634
1635 /***************************************
1636 ***************************************/
1637
1638 static void
input_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)1639 input_cb( FL_OBJECT * obj,
1640 long data FL_UNUSED_ARG )
1641 {
1642 obj->parent->returned = obj->returned;
1643 }
1644
1645
1646 /***************************************
1647 * Creates an input object
1648 ***************************************/
1649
1650 FL_OBJECT *
fl_create_input(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)1651 fl_create_input( int type,
1652 FL_Coord x,
1653 FL_Coord y,
1654 FL_Coord w,
1655 FL_Coord h,
1656 const char * label )
1657 {
1658 FL_OBJECT *obj;
1659 FLI_INPUT_SPEC *sp;
1660
1661 set_default_keymap( 0 );
1662
1663 obj = fl_make_object( FL_INPUT, type, x, y, w, h, label, handle_input );
1664 obj->boxtype = FL_INPUT_BOXTYPE;
1665 obj->col1 = FL_INPUT_COL1;
1666 obj->col2 = FL_INPUT_COL2;
1667 obj->align = FL_INPUT_ALIGN;
1668 obj->lcol = FL_INPUT_LCOL;
1669 obj->lsize = fli_cntl.inputFontSize ?
1670 fli_cntl.inputFontSize : FL_DEFAULT_SIZE;
1671 obj->set_return = fl_set_input_return;
1672
1673 fl_set_object_prehandler( obj, input_pre );
1674 fl_set_object_posthandler( obj, input_post );
1675
1676 obj->wantkey = obj->type == FL_MULTILINE_INPUT ?
1677 FL_KEY_ALL : FL_KEY_NORMAL;
1678 obj->want_update = 1;
1679 obj->input = 1;
1680 obj->click_timeout = FL_CLICK_TIMEOUT;
1681 obj->spec = sp = fl_calloc( 1, sizeof *sp );
1682
1683 sp->textcol = FL_INPUT_TCOL;
1684 sp->curscol = FL_INPUT_CCOL;
1685 sp->position = -1;
1686 sp->endrange = -1;
1687 sp->size = 8;
1688 sp->lines = sp->ypos = 1;
1689 sp->str = fl_malloc( sp->size );
1690 *sp->str = '\0';
1691 sp->cursor_visible = 1;
1692
1693 switch ( obj->type )
1694 {
1695 case FL_DATE_INPUT :
1696 sp->maxchars = 10;
1697 break;
1698
1699 case FL_SECRET_INPUT :
1700 sp->maxchars = 16;
1701 break;
1702
1703 default :
1704 sp->maxchars = 0;
1705 }
1706
1707 sp->dummy = obj;
1708 sp->input = obj;
1709 sp->field_char = ' ';
1710
1711 if ( obj->type == FL_INT_INPUT )
1712 sp->validate = int_validator;
1713 else if ( obj->type == FL_FLOAT_INPUT )
1714 sp->validate = float_validator;
1715 else if ( obj->type == FL_DATE_INPUT )
1716 {
1717 fl_set_input_format( obj, FL_INPUT_MMDD, '/' );
1718 sp->validate = date_validator;
1719 }
1720
1721 obj->how_return = FL_RETURN_END_CHANGED;
1722 fl_set_object_dblbuffer( obj, type != FL_HIDDEN_INPUT );
1723
1724 return obj;
1725 }
1726
1727
1728 /***************************************
1729 ***************************************/
1730
1731 static int
fake_handle(FL_OBJECT * obj,int event,FL_Coord mx FL_UNUSED_ARG,FL_Coord my FL_UNUSED_ARG,int key FL_UNUSED_ARG,void * ev FL_UNUSED_ARG)1732 fake_handle( FL_OBJECT * obj,
1733 int event,
1734 FL_Coord mx FL_UNUSED_ARG,
1735 FL_Coord my FL_UNUSED_ARG,
1736 int key FL_UNUSED_ARG,
1737 void * ev FL_UNUSED_ARG )
1738 {
1739 FLI_INPUT_SPEC *sp = obj->spec;
1740
1741 switch ( event )
1742 {
1743 case FL_ATTRIB:
1744 if ( sp->dummy != obj ) /* this can only happen with fdesign */
1745 sp->dummy = obj;
1746 copy_attributes( sp->input, sp->dummy );
1747 /* fall through */
1748
1749 case FL_DRAW:
1750 case FL_DRAWLABEL:
1751 check_scrollbar_size( obj );
1752 break;
1753 }
1754
1755 return 0;
1756 }
1757
1758
1759 /***************************************
1760 * Adds an input object
1761 ***************************************/
1762
1763 FL_OBJECT *
fl_add_input(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)1764 fl_add_input( int type,
1765 FL_Coord x,
1766 FL_Coord y,
1767 FL_Coord w,
1768 FL_Coord h,
1769 const char * label )
1770 {
1771 FL_OBJECT *obj;
1772 FLI_INPUT_SPEC *sp;
1773 int oldu = fl_get_coordunit( );
1774
1775 obj = fl_create_input( type, x, y, w, h, label );
1776 sp = obj->spec;
1777
1778 fl_set_coordunit( FL_COORD_PIXEL );
1779
1780 x = obj->x;
1781 y = obj->y;
1782 w = obj->w;
1783 h = obj->h;
1784
1785 if ( obj->type == FL_MULTILINE_INPUT )
1786 {
1787 fl_set_object_label( obj, NULL );
1788 sp->dummy = fl_create_box( FL_NO_BOX, x, y, w, h, label );
1789 sp->dummy->objclass = FL_INPUT;
1790 sp->dummy->type = FL_MULTILINE_INPUT;
1791 copy_attributes( sp->dummy, obj );
1792 sp->dummy->handle = fake_handle;
1793 sp->dummy->spec = sp;
1794 sp->dummy->set_return = fl_set_input_return;
1795
1796 fl_add_child( sp->dummy, obj );
1797
1798 sp->hh_def = sp->vw_def = fli_get_default_scrollbarsize( obj );
1799 sp->h_pref = sp->v_pref = FL_AUTO;
1800 sp->vscroll = fl_create_scrollbar( fli_context->vscb,
1801 x + w - sp->vw_def,
1802 y, sp->vw_def, h, NULL );
1803 fl_set_scrollbar_value( sp->vscroll, 0.0 );
1804 fl_set_object_callback( sp->vscroll, vsl_cb, 0 );
1805 fl_set_object_resize( sp->vscroll, FL_RESIZE_NONE );
1806 fl_add_child( sp->dummy, sp->vscroll );
1807
1808 sp->hscroll = fl_create_scrollbar( fli_context->hscb, x,
1809 y + h - sp->hh_def,
1810 w, sp->hh_def, NULL );
1811 fl_set_scrollbar_value( sp->hscroll, 0.0 );
1812 fl_set_object_callback( sp->hscroll, hsl_cb, 0 );
1813 fl_set_object_resize( sp->hscroll, FL_RESIZE_NONE );
1814 fl_add_child( sp->dummy, sp->hscroll );
1815
1816 fl_set_object_callback( sp->input, input_cb, 0 );
1817 fl_set_object_return( sp->dummy, FL_RETURN_END_CHANGED );
1818 }
1819
1820 fl_add_object( fl_current_form, sp->dummy );
1821
1822 fl_set_coordunit( oldu );
1823
1824 /* Set default return policy for the new object */
1825
1826 fl_set_object_return( obj, FL_RETURN_END_CHANGED );
1827
1828 return sp->dummy;
1829 }
1830
1831
1832 /***************************************
1833 * Sets the input string. Only printable character and, for multi-line
1834 * inputs new-lines are accepted.
1835 ***************************************/
1836
1837 #define IS_VALID_INPUT_CHAR( c ) \
1838 isprint( ( unsigned char ) ( c ) ) \
1839 || ( obj->type == FL_MULTILINE_INPUT && ( c ) == '\n' )
1840
1841 void
fl_set_input(FL_OBJECT * obj,const char * str)1842 fl_set_input( FL_OBJECT * obj,
1843 const char * str )
1844 {
1845 FLI_INPUT_SPEC *sp = obj->spec;
1846 int len;
1847 char *p;
1848 const char *q;
1849
1850 if ( ! str )
1851 str = "";
1852
1853 for ( len = 0, q = str; *q; ++q )
1854 if ( IS_VALID_INPUT_CHAR( *q ) )
1855 ++len;
1856
1857 if ( sp->size < len + 1 )
1858 {
1859 sp->size = len + 9;
1860 sp->str = fl_realloc( sp->str, sp->size );
1861 }
1862
1863 for ( p = sp->str, q = str; *q; ++q )
1864 if ( IS_VALID_INPUT_CHAR( *q ) )
1865 *p++ = *q;
1866 *p = '\0';
1867
1868 /* Set position of cursor in string to the end (if object doesn't has
1869 focus must be negative of length of strig minus one) */
1870
1871 if ( sp->position >= 0 )
1872 sp->position = len;
1873 else
1874 sp->position = - len - 1;
1875
1876 sp->endrange = -1;
1877
1878 sp->lines = fl_get_input_numberoflines( obj );
1879 fl_get_input_cursorpos( obj, &sp->xpos, &sp->ypos );
1880
1881 /* Get max string width - it's possible that fl_set_input() is used before
1882 the form is show, draw_object is a no-op, thus we end up with a wrong
1883 string size */
1884
1885 fl_get_string_dimension( obj->lstyle, obj->lsize,
1886 sp->str, len, &sp->max_pixels, &len );
1887
1888 if ( obj->form )
1889 fl_freeze_form( obj->form );
1890
1891 check_scrollbar_size( obj );
1892 make_line_visible( obj, sp->ypos );
1893 fl_redraw_object( sp->input );
1894 sp->xoffset = 0;
1895 check_scrollbar_size( obj );
1896 if ( sp->v_on || sp->h_on )
1897 redraw_scrollbar( obj );
1898
1899 if ( obj->form )
1900 fl_unfreeze_form( obj->form );
1901 }
1902
1903
1904 /***************************************
1905 * Sets the input string using a format string and an appropriate number
1906 * of (unspecified) arguments
1907 ***************************************/
1908
1909 void
fl_set_input_f(FL_OBJECT * obj,const char * fmt,...)1910 fl_set_input_f( FL_OBJECT * obj,
1911 const char * fmt,
1912 ... )
1913 {
1914 char *buf;
1915
1916 EXPAND_FORMAT_STRING( buf, fmt );
1917 fl_set_input( obj, buf );
1918 fl_free( buf );
1919 }
1920
1921
1922 /***************************************
1923 * Sets the color of the input string
1924 ***************************************/
1925
1926 void
fl_set_input_color(FL_OBJECT * obj,FL_COLOR textcol,FL_COLOR curscol)1927 fl_set_input_color( FL_OBJECT * obj,
1928 FL_COLOR textcol,
1929 FL_COLOR curscol )
1930 {
1931 FLI_INPUT_SPEC *sp = obj->spec;
1932
1933 sp->textcol = textcol;
1934 sp->curscol = curscol;
1935 fl_redraw_object( sp->input );
1936 }
1937
1938
1939 /***************************************
1940 * Returns the color of the input string
1941 ***************************************/
1942
1943 void
fl_get_input_color(FL_OBJECT * obj,FL_COLOR * textcol,FL_COLOR * curscol)1944 fl_get_input_color( FL_OBJECT * obj,
1945 FL_COLOR * textcol,
1946 FL_COLOR * curscol )
1947 {
1948 FLI_INPUT_SPEC *sp = obj->spec;
1949
1950 *textcol = sp->textcol;
1951 *curscol = sp->curscol;
1952 }
1953
1954
1955 /***************************************
1956 ***************************************/
1957
1958 int
fl_set_input_fieldchar(FL_OBJECT * obj,int fchar)1959 fl_set_input_fieldchar( FL_OBJECT * obj,
1960 int fchar )
1961 {
1962 FLI_INPUT_SPEC *sp = obj->spec;
1963 int ochar = sp->field_char;
1964
1965 if ( obj->objclass != FL_INPUT )
1966 {
1967 M_err( "fl_set_input_fieldchar", "%s isn't an input object",
1968 obj ? obj->label : "null" );
1969 return 0;
1970 }
1971
1972 sp->field_char = fchar;
1973 return ochar;
1974 }
1975
1976
1977 /***************************************
1978 * Returns a pointer to the text string
1979 ***************************************/
1980
1981 const char *
fl_get_input(FL_OBJECT * obj)1982 fl_get_input( FL_OBJECT * obj )
1983 {
1984 return ( ( FLI_INPUT_SPEC * ) obj->spec )->str;
1985 }
1986
1987
1988 /***************************************
1989 * Sets under which conditions the object is to be returned to the
1990 * application. This function should be regarded as for internal use
1991 * only and fl_set_object_return() should be used instead (which then
1992 * will call this function).
1993 ***************************************/
1994
1995 void
fl_set_input_return(FL_OBJECT * obj,unsigned int when)1996 fl_set_input_return( FL_OBJECT * obj,
1997 unsigned int when )
1998 {
1999 FLI_INPUT_SPEC *sp = obj->spec;
2000
2001 if ( when & FL_RETURN_END_CHANGED )
2002 when &= ~ ( FL_RETURN_END | FL_RETURN_CHANGED );
2003
2004 obj->how_return = sp->input->how_return = when;
2005 fl_set_object_return( sp->vscroll, FL_RETURN_CHANGED );
2006 fl_set_object_return( sp->hscroll, FL_RETURN_CHANGED );
2007 }
2008
2009
2010 /***************************************
2011 ***************************************/
2012
2013 void
fl_set_input_scroll(FL_OBJECT * obj,int yes)2014 fl_set_input_scroll( FL_OBJECT * obj,
2015 int yes )
2016 {
2017 ( ( FLI_INPUT_SPEC * ) obj->spec )->noscroll = ! yes;
2018 }
2019
2020
2021 /***************************************
2022 * Makes a part of an input string selected or deselected
2023 ***************************************/
2024
2025 void
fl_set_input_selected_range(FL_OBJECT * obj,int begin,int end)2026 fl_set_input_selected_range( FL_OBJECT * obj,
2027 int begin,
2028 int end )
2029 {
2030 FLI_INPUT_SPEC *sp = obj->spec;
2031 int len;
2032
2033 if ( obj->type == FL_HIDDEN_INPUT )
2034 return;
2035
2036 len = strlen( sp->str );
2037
2038 if ( begin < 0 )
2039 sp->beginrange = 0;
2040 else if ( begin > len )
2041 sp->beginrange = len;
2042 else
2043 sp->beginrange = begin;
2044
2045 if ( end < 0 )
2046 sp->endrange = -1;
2047 else if ( end > len )
2048 sp->endrange = len;
2049 else
2050 sp->endrange = end;
2051
2052 /* move cursor to the head */
2053
2054 sp->position = sp->beginrange;
2055 fl_redraw_object( sp->input );
2056 }
2057
2058
2059 /***************************************
2060 ***************************************/
2061
2062 const char *
fl_get_input_selected_range(FL_OBJECT * obj,int * begin,int * end)2063 fl_get_input_selected_range( FL_OBJECT * obj,
2064 int * begin,
2065 int * end )
2066 {
2067 FLI_INPUT_SPEC *sp = obj->spec;
2068 static char *selbuf;
2069 static int nselbuf;
2070 int n;
2071
2072 n = sp->endrange - sp->beginrange;
2073
2074 if ( n < 1 )
2075 {
2076 if ( begin )
2077 *begin = -1;
2078 if ( end )
2079 *end = -1;
2080 return NULL;
2081 }
2082
2083 if ( begin )
2084 *begin = sp->beginrange;
2085
2086 if ( end )
2087 *end = sp->endrange;
2088
2089 if ( n != nselbuf )
2090 {
2091 selbuf = fl_realloc( selbuf, n + 1 );
2092 nselbuf = n;
2093 }
2094
2095 fli_sstrcpy( selbuf, sp->str + sp->beginrange, n );
2096
2097 return selbuf;
2098 }
2099
2100
2101 /***************************************
2102 * Selects the current input programmatically without moving
2103 * the cursor
2104 ***************************************/
2105
2106 void
fl_set_input_selected(FL_OBJECT * obj,int yes)2107 fl_set_input_selected( FL_OBJECT * obj,
2108 int yes )
2109 {
2110 FLI_INPUT_SPEC *sp = obj->spec;
2111
2112 if ( obj->type == FL_HIDDEN_INPUT )
2113 return;
2114
2115 if ( yes )
2116 {
2117 sp->position = sp->endrange = strlen( sp->str );
2118 sp->beginrange = 0;
2119 }
2120 else
2121 sp->endrange = -1;
2122
2123 fl_redraw_object( sp->input );
2124 }
2125
2126
2127 /***************************************
2128 * Given an (x,y) location returns the string position in chars
2129 ***************************************/
2130
2131 static int
xytopos(FLI_INPUT_SPEC * sp,int xpos,int ypos)2132 xytopos( FLI_INPUT_SPEC * sp,
2133 int xpos,
2134 int ypos )
2135 {
2136 int newp = 0;
2137 char *s = sp->str,
2138 *se = s + strlen( s );
2139
2140 if ( ypos < 1 )
2141 ypos = 1;
2142 else if ( ypos > sp->lines )
2143 ypos = sp->lines;
2144
2145 if ( xpos < 0 )
2146 xpos = 0;
2147
2148 sp->ypos = 1;
2149 while ( sp->ypos < ypos && ( s = strchr( s, '\n' ) ) )
2150 {
2151 sp->ypos++;
2152 s++;
2153 newp = s - sp->str;
2154 }
2155
2156 s = sp->str + newp;
2157 for ( sp->xpos = 0; sp->xpos < xpos && s < se; sp->xpos++, newp++ )
2158 if ( *++s == '\n' )
2159 break;
2160
2161 return sp->position = newp;
2162 }
2163
2164
2165 /***************************************
2166 * Move cursor within the input field, cursor position is measured in chars
2167 ***************************************/
2168
2169 void
fl_set_input_cursorpos(FL_OBJECT * obj,int xpos,int ypos)2170 fl_set_input_cursorpos( FL_OBJECT * obj,
2171 int xpos,
2172 int ypos )
2173 {
2174 FLI_INPUT_SPEC *sp = obj->spec;
2175 int oldp = sp->position;
2176
2177 if ( obj->type == FL_HIDDEN_INPUT )
2178 return;
2179
2180 if ( oldp != xytopos( sp, xpos, ypos ) )
2181 {
2182 fl_freeze_form( obj->form );
2183 make_line_visible( obj, sp->ypos );
2184 make_char_visible( obj, sp->xpos );
2185 fl_redraw_object( obj );
2186 fl_unfreeze_form( obj->form );
2187 }
2188 }
2189
2190
2191 /***************************************
2192 ***************************************/
2193
2194 int
fl_get_input_cursorpos(FL_OBJECT * obj,int * x,int * y)2195 fl_get_input_cursorpos( FL_OBJECT * obj,
2196 int * x,
2197 int * y )
2198 {
2199 FLI_INPUT_SPEC *sp = obj->spec;
2200 char *s = sp->str;
2201 int cnt = 0;
2202
2203 if ( ! obj->focus )
2204 return sp->position = *x = -1;
2205
2206 *y = 1;
2207 *x = 0;
2208
2209 for ( ; s && *s && cnt < sp->position; s++, cnt++ )
2210 if ( *s == '\n' )
2211 {
2212 *y += 1;
2213 *x = 0;
2214 }
2215 else
2216 *x += 1;
2217
2218 return sp->position;
2219 }
2220
2221
2222 /***************************************
2223 * Reverts to the default keymap for edit keys
2224 ***************************************/
2225
2226 void
fl_set_default_editkeymap(void)2227 fl_set_default_editkeymap( void )
2228 {
2229 set_default_keymap( 1 );
2230 }
2231
2232
2233 #define Ctrl( c ) \
2234 ( ( tolower( ( unsigned char ) c ) - 'a' + 1 ) | FL_CONTROL_MASK )
2235 #define Meta( c ) ( tolower( ( unsigned char ) c ) | FL_ALT_MASK )
2236
2237 /***************************************
2238 ***************************************/
2239
2240 static void
set_default_keymap(int force)2241 set_default_keymap( int force )
2242 {
2243 static int initialized = 0;
2244
2245 if ( ! force && initialized )
2246 return;
2247
2248 initialized = 1;
2249
2250 /* Emacs defaults */
2251
2252 kmap.moveto_next_char = Ctrl( 'f' );
2253 kmap.moveto_prev_char = Ctrl( 'b' );
2254 kmap.moveto_prev_word = Meta( 'b' );
2255 kmap.moveto_next_word = Meta( 'f' );
2256
2257 kmap.moveto_bol = Ctrl( 'a' );
2258 kmap.moveto_eol = Ctrl( 'e' );
2259
2260 kmap.moveto_next_line = Ctrl( 'n' );
2261 kmap.moveto_prev_line = Ctrl( 'p' );
2262
2263 kmap.moveto_bof = Meta( '<' );
2264 kmap.moveto_eof = Meta( '>' );
2265
2266 kmap.del_next_char = Ctrl( 'd' );
2267 kmap.del_prev_char = Ctrl( 'h' );
2268 kmap.del_next_word = Meta( 'd' );
2269 kmap.del_prev_word = Meta( '\b' );
2270
2271 kmap.del_to_eol = Ctrl( 'k' );
2272 kmap.del_to_bol = Meta( 'k' );
2273
2274 kmap.backspace = '\b';
2275 kmap.transpose = Ctrl( 't' );
2276 kmap.paste = Ctrl( 'y' );
2277 kmap.clear_field = Ctrl( 'u' );
2278 }
2279
2280
2281 /***************************************
2282 ***************************************/
2283
2284 void
fl_set_input_maxchars(FL_OBJECT * obj,int maxchars)2285 fl_set_input_maxchars( FL_OBJECT * obj,
2286 int maxchars )
2287 {
2288 ( ( FLI_INPUT_SPEC * ) obj->spec )->maxchars = maxchars;
2289 }
2290
2291
2292 /***************************************
2293 ***************************************/
2294
2295 FL_INPUT_VALIDATOR
fl_set_input_filter(FL_OBJECT * obj,FL_INPUT_VALIDATOR validate)2296 fl_set_input_filter( FL_OBJECT * obj,
2297 FL_INPUT_VALIDATOR validate )
2298 {
2299 FLI_INPUT_SPEC *sp = obj->spec;
2300 FL_INPUT_VALIDATOR old = sp->validate;
2301
2302 sp->validate = validate;
2303 return old;
2304 }
2305
2306
2307 /***************************************
2308 ***************************************/
2309
2310 void
fl_set_input_format(FL_OBJECT * obj,int fmt,int sep)2311 fl_set_input_format( FL_OBJECT * obj,
2312 int fmt,
2313 int sep )
2314 {
2315 FLI_INPUT_SPEC *sp = obj->spec;
2316
2317 if ( ! isprint( ( unsigned char ) sep )
2318 || isdigit( ( unsigned char ) sep ) )
2319 sep = '/';
2320 sp->attrib1 = fmt;
2321 sp->attrib2 = sep;
2322 }
2323
2324
2325 /***************************************
2326 ***************************************/
2327
2328 void
fl_get_input_format(FL_OBJECT * obj,int * fmt,int * sep)2329 fl_get_input_format( FL_OBJECT * obj,
2330 int * fmt,
2331 int * sep )
2332 {
2333 FLI_INPUT_SPEC *sp = obj->spec;
2334
2335 *fmt = sp->attrib1;
2336 *sep = sp->attrib2;
2337 }
2338
2339
2340 /***************************************
2341 ***************************************/
2342
2343 int
fl_validate_input(FL_OBJECT * obj)2344 fl_validate_input( FL_OBJECT *obj )
2345 {
2346 FLI_INPUT_SPEC *sp = obj->spec;
2347
2348 return ( ! sp->validate
2349 || sp->validate( obj, sp->str, sp->str, 0 ) == FL_VALID ) ?
2350 FL_VALID : FL_INVALID;
2351 }
2352
2353
2354 /***************************************
2355 * Validator for date
2356 ***************************************/
2357
2358 #define IS_LEAP_YEAR( y ) \
2359 ( ( y ) % 4 == 0 && ( ( y ) % 100 != 0 || ( y ) % 400 == 0 ) )
2360
2361 static int
date_validator(FL_OBJECT * obj,const char * oldstr FL_UNUSED_ARG,const char * newstr,int newc)2362 date_validator( FL_OBJECT * obj,
2363 const char * oldstr FL_UNUSED_ARG,
2364 const char * newstr,
2365 int newc )
2366 {
2367 char *val,
2368 *s,
2369 sepsep[ 3 ];
2370 char ssep[ 2 ] = "";
2371 int i,
2372 len,
2373 ival[ ] = { 1, 1, 1 };
2374 int fmt,
2375 sep;
2376 int invalid = FL_RINGBELL | FL_INVALID;
2377 int m,
2378 d;
2379
2380 /* Consider empty valid */
2381
2382 if ( ( len = strlen( newstr ) ) == 0 )
2383 return FL_VALID;
2384
2385 fl_get_input_format( obj, &fmt, &sep );
2386
2387 *ssep = sep;
2388 strcat( strcpy( sepsep, ssep ), ssep );
2389
2390
2391 /* Allow only separator or digit, but no separator at the very start or
2392 two separators in a row */
2393
2394 if ( ( newc != sep
2395 && newc != '\0'
2396 && ! isdigit( ( unsigned char ) newc ) )
2397 || *newstr == sep || strstr( newstr, sepsep ) )
2398 return invalid;
2399
2400 s = fl_strdup( newstr );
2401
2402 /* Split up the date string at the separators and convert to ints and
2403 check that there aren't more than 2 digits for day and month and 4
2404 for the year */
2405
2406 for ( i = 0, val = strtok( s, ssep ); i < 3 && val;
2407 val = strtok( NULL, ssep ) )
2408 {
2409 if ( ( i < 2 && strlen( val ) > 2 ) || ( i == 2 && strlen( val ) > 4 ) )
2410 return invalid;
2411
2412 ival[ i++ ] = atoi( val );
2413
2414 if ( i <= 2 && strlen( val ) == 2 && ival[ i - 1 ] == 0 )
2415 return invalid;
2416 }
2417
2418 fl_free( s );
2419
2420 /* Allow one or more '0' at the start of the day pr month (but not as
2421 the only digit, i.e. when the new character is the separator) */
2422
2423 if ( newc == sep
2424 && ( ( i == 1 && ival[ 0 ] == 0 )
2425 || ( i == 2 && ival[ 1 ] == 0 ) ) )
2426 return invalid;
2427
2428 /* Don't allow another separator when we already got 3 items */
2429
2430 if ( i == 3 && newstr[ len - 1 ] == sep )
2431 return invalid;
2432
2433 /* Always require 3 items when the user tries to leave the field
2434 and make sure that day or month aren't 0 */
2435
2436 if ( newc == '\0'
2437 && ( i != 3 || ival[ 0 ] == 0 || ival[ 1 ] == 0 ) )
2438 return invalid;
2439
2440 m = fmt == FL_INPUT_MMDD ? 0 : 1;
2441 d = ! m;
2442
2443 /* Basic check for upper limits of day and month */
2444
2445 if ( ival[ m ] > 12 || ival[ d ] > 31 )
2446 return invalid;
2447
2448 /* More precise check for days in month */
2449
2450 if ( ( ival[ d ] > 30 && ( ival[ m ] % 2 ) == 0 && ival[ m ] < 8 )
2451 || ( ival[ d ] > 30 && ( ival[ m ] % 2 ) != 0 && ival[ m ] > 8 ) )
2452 return invalid;
2453
2454 /* Take care: check for leap year can only be done when leaving */
2455
2456 if ( ival[ m ] == 2
2457 && ( ival[ d ] > 29
2458 || ( i == 3
2459 && newc == 0
2460 && ival[ d ] > 28
2461 && ! IS_LEAP_YEAR( ival[ 2 ] ) ) ) )
2462 return invalid;
2463
2464 return FL_VALID;
2465 }
2466
2467
2468 /***************************************
2469 * Validator for integer fields
2470 ***************************************/
2471
2472 static int
int_validator(FL_OBJECT * obj FL_UNUSED_ARG,const char * oldstr FL_UNUSED_ARG,const char * str,int newc)2473 int_validator( FL_OBJECT * obj FL_UNUSED_ARG,
2474 const char * oldstr FL_UNUSED_ARG,
2475 const char * str,
2476 int newc )
2477 {
2478 char *eptr = NULL;
2479 long dummy;
2480
2481 /* The empty string is considered to be valid */
2482
2483 if ( ! *str )
2484 return FL_VALID;
2485
2486 /* If there was a new character and all we got is a '+' or '-' this is ok */
2487
2488 if ( ! str[ 1 ] && ( newc == '+' || newc == '-' ) )
2489 return FL_VALID;
2490
2491 dummy = strtol( str, &eptr, 10 );
2492
2493 if ( ( ( dummy == LONG_MAX || dummy == LONG_MIN ) && errno == ERANGE )
2494 || *eptr )
2495 return FL_INVALID | FL_RINGBELL;
2496
2497 return FL_VALID;
2498 }
2499
2500
2501 /***************************************
2502 * Validator for floating point fields
2503 ***************************************/
2504
2505 static int
float_validator(FL_OBJECT * obj FL_UNUSED_ARG,const char * oldstr FL_UNUSED_ARG,const char * str,int newc)2506 float_validator( FL_OBJECT * obj FL_UNUSED_ARG,
2507 const char * oldstr FL_UNUSED_ARG,
2508 const char * str,
2509 int newc )
2510 {
2511 char *eptr = NULL;
2512 size_t len;
2513 double dummy;
2514
2515 /* The empty string is considered valid */
2516
2517 if ( ! *str )
2518 return FL_VALID;
2519
2520 /* Try strtod() an the string*/
2521
2522 dummy = strtod( str, &eptr );
2523
2524 /* If it reports no problem were done */
2525
2526 if ( ! ( ( dummy == HUGE_VAL || dummy == -HUGE_VAL ) && errno == ERANGE )
2527 && ! *eptr )
2528 return FL_VALID;
2529
2530 /* Otherwise, if there's no new character the input must be invalid */
2531
2532 if ( ! newc )
2533 return FL_INVALID | FL_RINGBELL;
2534
2535 /* Now we handle cases that strtod() flagged as bad but which we need to
2536 accept while editing is still underway. If there's only a single char
2537 it should be a dot or a sign */
2538
2539 len = strlen( str );
2540
2541 if ( len == 1 )
2542 return ( newc == '+' || newc == '-' || newc == '.' ) ?
2543 FL_VALID : FL_INVALID | FL_RINGBELL;
2544
2545 /* If there are two characters accept a sequence of a sign and a decimal
2546 point or a number followed by 'e' or 'E' */
2547
2548 if ( len == 2 )
2549 return ( ! strcmp( str, "+." )
2550 || ! strcmp( str, "-." )
2551 || *eptr == 'e'
2552 || *eptr == 'E' ) ?
2553 FL_VALID : ( FL_INVALID | FL_RINGBELL );
2554
2555 /* Accept an 'e' or 'E' in the last position, or, if it's in the second last
2556 position, when it's followed by a sign - but only if it's the first 'e'
2557 or 'E' in the string */
2558
2559 if ( ( *eptr == 'e' || *eptr == 'E' )
2560 && strchr( str, *eptr ) == eptr
2561 && ( eptr == str + len - 1
2562 || ( eptr == str + len - 2
2563 && ( eptr[ 1 ] == '+' || eptr[ 1 ] == '-' ) ) ) )
2564 return FL_VALID;
2565
2566 return FL_INVALID | FL_RINGBELL;
2567 }
2568
2569
2570 /***************************************
2571 ***************************************/
2572
2573 void
fl_set_input_xoffset(FL_OBJECT * obj,int xoff)2574 fl_set_input_xoffset( FL_OBJECT * obj,
2575 int xoff )
2576 {
2577 FLI_INPUT_SPEC *sp = obj->spec;
2578
2579 if ( sp->xoffset != xoff )
2580 {
2581 sp->xoffset = xoff;
2582 if ( sp->drawtype != HSLIDER )
2583 {
2584 check_scrollbar_size( obj );
2585 redraw_scrollbar( obj );
2586 }
2587 sp->drawtype = COMPLETE;
2588 fl_redraw_object( sp->input );
2589 }
2590 }
2591
2592
2593 /***************************************
2594 ***************************************/
2595
2596 int
fl_get_input_xoffset(FL_OBJECT * obj)2597 fl_get_input_xoffset( FL_OBJECT * obj )
2598 {
2599 return ( ( FLI_INPUT_SPEC * ) obj->spec )->xoffset;
2600 }
2601
2602
2603 /***************************************
2604 * Corrects, if necessary, the value of 'top' (the topmost line to be
2605 * shown in a FL_MULTILINE_INPUT object, count is starting at 1) so
2606 * that the value is at least 1 and, if there are less lines below
2607 * 'top' then fit into the input field, adjusts 'top' that the
2608 * complete field is used (i.e. there are no empty lines at the end).
2609 ***************************************/
2610
2611 static void
correct_topline(FLI_INPUT_SPEC * sp,int * top)2612 correct_topline( FLI_INPUT_SPEC * sp,
2613 int * top )
2614 {
2615 if ( sp->lines > sp->screenlines )
2616 {
2617 if ( sp->lines < *top + sp->screenlines - 1 )
2618 *top = sp->lines - sp->screenlines + 1;
2619 if ( *top < 1 )
2620 *top = 1;
2621 }
2622 else
2623 *top = 1;
2624 }
2625
2626
2627 /***************************************
2628 ***************************************/
2629
2630 int
fl_get_input_numberoflines(FL_OBJECT * obj)2631 fl_get_input_numberoflines( FL_OBJECT * obj )
2632 {
2633 FLI_INPUT_SPEC *sp = obj->spec;
2634 int count;
2635 const char *s = sp->str;
2636
2637 if ( ! s )
2638 return sp->lines = 0;
2639
2640 for ( count = 1; *s; s++ )
2641 if ( *s == '\n' )
2642 count++;
2643
2644 return sp->lines = count;
2645 }
2646
2647
2648 /***************************************
2649 * Makes the requested line 'top' (starting at 1) the topmost line
2650 * shown in a FL_MULTILINE_INPUT object.
2651 ***************************************/
2652
2653 void
fl_set_input_topline(FL_OBJECT * obj,int top)2654 fl_set_input_topline( FL_OBJECT * obj,
2655 int top )
2656 {
2657 FLI_INPUT_SPEC *sp = obj->spec;
2658
2659 if ( sp->input->type != FL_MULTILINE_INPUT )
2660 return;
2661
2662 correct_topline( sp, &top );
2663
2664 if ( sp->topline == top )
2665 return;
2666
2667 /* Make sure the cursor remains in a visible line */
2668
2669 if ( sp->ypos < top || sp->ypos >= top + sp->screenlines )
2670 {
2671 if ( sp->ypos < top )
2672 xytopos( sp, sp->xpos, top );
2673 else
2674 xytopos( sp, sp->xpos, top + sp->screenlines - 1 );
2675 make_char_visible( obj, sp->xpos );
2676 }
2677
2678 sp->topline = top;
2679 if ( sp->drawtype != VSLIDER )
2680 {
2681 check_scrollbar_size( obj );
2682 redraw_scrollbar( obj );
2683 }
2684
2685 sp->drawtype = COMPLETE;
2686 sp->yoffset = ( sp->topline - 1 ) * sp->charh;
2687 fl_redraw_object( sp->input );
2688 }
2689
2690
2691 /***************************************
2692 * Line number 'n' is numbered from 1.
2693 ***************************************/
2694
2695 static int
make_line_visible(FL_OBJECT * obj,int ypos)2696 make_line_visible( FL_OBJECT * obj,
2697 int ypos )
2698 {
2699 FLI_INPUT_SPEC *sp = obj->spec;
2700 int oldtop = sp->topline;
2701
2702 if ( obj->type != FL_MULTILINE_INPUT )
2703 return 0;
2704
2705 if ( ypos < sp->topline )
2706 fl_set_input_topline( obj, ypos );
2707 else if ( ypos > sp->topline + sp->screenlines - 1 )
2708 fl_set_input_topline( obj, ypos - sp->screenlines + 1 );
2709 else if ( sp->lines < sp->screenlines )
2710 fl_set_input_topline( obj, 1 );
2711
2712 return oldtop != sp->topline;
2713 }
2714
2715
2716 /***************************************
2717 ***************************************/
2718
2719 static int
make_char_visible(FL_OBJECT * obj,int xpos)2720 make_char_visible( FL_OBJECT * obj,
2721 int xpos )
2722 {
2723 FLI_INPUT_SPEC *sp = obj->spec;
2724 int start_of_line = sp->position;
2725 int oldxoffset = sp->xoffset;
2726 int tmp;
2727
2728 if ( xpos < 0 )
2729 return 0;
2730
2731 while ( start_of_line > 0 && sp->str[ start_of_line - 1 ] != '\n' )
2732 start_of_line--;
2733
2734 tmp = get_substring_width( obj, start_of_line, start_of_line + xpos );
2735
2736 if ( tmp < sp->xoffset )
2737 sp->xoffset = tmp;
2738 else if ( tmp - sp->xoffset > sp->w )
2739 sp->xoffset = tmp - sp->w;
2740
2741 if ( sp->xoffset != oldxoffset )
2742 {
2743 check_scrollbar_size( obj );
2744 redraw_scrollbar( obj );
2745 fl_redraw_object( sp->input );
2746 return 1;
2747 }
2748
2749 return 0;
2750 }
2751
2752
2753 /***************************************
2754 ***************************************/
2755
2756 void
fl_set_input_vscrollbar(FL_OBJECT * obj,int pref)2757 fl_set_input_vscrollbar( FL_OBJECT * obj,
2758 int pref )
2759 {
2760 FLI_INPUT_SPEC *sp = obj->spec;
2761
2762 if ( sp->v_pref != pref )
2763 {
2764 sp->v_pref = pref;
2765 check_scrollbar_size( obj );
2766 redraw_scrollbar( obj );
2767 fl_redraw_object( sp->input );
2768 }
2769 }
2770
2771
2772 /***************************************
2773 ***************************************/
2774
2775 void
fl_set_input_hscrollbar(FL_OBJECT * obj,int pref)2776 fl_set_input_hscrollbar( FL_OBJECT * obj,
2777 int pref )
2778 {
2779 FLI_INPUT_SPEC *sp = obj->spec;
2780
2781 if ( sp->h_pref != pref )
2782 {
2783 sp->h_pref = pref;
2784 check_scrollbar_size( obj );
2785 redraw_scrollbar( obj );
2786 fl_redraw_object( sp->input );
2787 }
2788 }
2789
2790
2791 /***************************************
2792 ***************************************/
2793
2794 void
fl_set_input_scrollbarsize(FL_OBJECT * obj,int hh,int vw)2795 fl_set_input_scrollbarsize( FL_OBJECT * obj,
2796 int hh,
2797 int vw )
2798 {
2799 FLI_INPUT_SPEC *sp = obj->spec;
2800
2801 if ( sp->hh_def != hh || sp->vw_def != vw )
2802 {
2803 sp->hh_def = hh;
2804 sp->vw_def = vw;
2805 check_scrollbar_size( obj );
2806 redraw_scrollbar( obj );
2807 fl_redraw_object( sp->input );
2808 }
2809 }
2810
2811
2812 /***************************************
2813 ***************************************/
2814
2815 void
fl_get_input_scrollbarsize(FL_OBJECT * obj,int * hh,int * vw)2816 fl_get_input_scrollbarsize( FL_OBJECT * obj,
2817 int * hh,
2818 int * vw )
2819 {
2820 FLI_INPUT_SPEC *sp = obj->spec;
2821
2822 *hh = sp->hh_def;
2823 *vw = sp->vw_def;
2824 }
2825
2826
2827 /***************************************
2828 ***************************************/
2829
2830 int
fl_get_input_topline(FL_OBJECT * obj)2831 fl_get_input_topline( FL_OBJECT * obj )
2832 {
2833 FLI_INPUT_SPEC *sp = obj->spec;
2834
2835 if ( sp->input->type != FL_MULTILINE_INPUT )
2836 return 1;
2837
2838 return sp->topline;
2839 }
2840
2841
2842 /***************************************
2843 ***************************************/
2844
2845 int
fl_get_input_screenlines(FL_OBJECT * obj)2846 fl_get_input_screenlines( FL_OBJECT * obj )
2847 {
2848 return ( ( FLI_INPUT_SPEC * ) obj->spec )->screenlines;
2849 }
2850
2851
2852 #define SetKey( m ) if ( keymap->m ) kmap.m = keymap->m
2853
2854
2855 /***************************************
2856 ***************************************/
2857
2858 void
fl_set_input_editkeymap(const FL_EditKeymap * keymap)2859 fl_set_input_editkeymap( const FL_EditKeymap * keymap )
2860 {
2861 /* If keymap is Null force default */
2862
2863 if ( ! keymap )
2864 {
2865 set_default_keymap( 1 );
2866 return;
2867 }
2868
2869 set_default_keymap( 0 );
2870
2871 SetKey( del_prev_char );
2872 SetKey( del_next_char );
2873 SetKey( del_prev_word );
2874 SetKey( del_next_word );
2875
2876 SetKey( moveto_prev_char );
2877 SetKey( moveto_next_char );
2878 SetKey( moveto_prev_word );
2879 SetKey( moveto_next_word );
2880 SetKey( moveto_prev_line );
2881 SetKey( moveto_next_line );
2882 SetKey( moveto_bof );
2883 SetKey( moveto_eof );
2884 SetKey( moveto_bol );
2885 SetKey( moveto_eol );
2886
2887 SetKey( backspace );
2888 SetKey( clear_field );
2889 SetKey( paste );
2890 SetKey( transpose );
2891 SetKey( del_to_eos );
2892 SetKey( del_to_eol );
2893 SetKey( del_to_bol );
2894 }
2895
2896
2897 /***************************************
2898 ***************************************/
2899
2900 void
fl_get_input_editkeymap(FL_EditKeymap * keymap)2901 fl_get_input_editkeymap( FL_EditKeymap * keymap )
2902 {
2903 /* Don't do anything if we got a NULL pointer */
2904
2905 if ( ! keymap )
2906 return;
2907
2908 /* Make sure the keymap is set up */
2909
2910 set_default_keymap( 0 );
2911
2912 /* Copy the current keymap to the user supplied buffer */
2913
2914 memcpy( keymap, &kmap, sizeof kmap );
2915 }
2916
2917
2918 /***************************************
2919 ***************************************/
2920
2921 static void
copy_attributes(FL_OBJECT * dest,const FL_OBJECT * src)2922 copy_attributes( FL_OBJECT * dest,
2923 const FL_OBJECT * src )
2924 {
2925 if ( src == dest )
2926 return;
2927
2928 dest->col1 = src->col1;
2929 dest->col2 = src->col2;
2930 dest->align = src->align;
2931 dest->boxtype = src->boxtype;
2932 dest->lcol = src->lcol;
2933 dest->lstyle = src->lstyle;
2934 dest->lsize = src->lsize;
2935 }
2936
2937
2938 /***************************************
2939 ***************************************/
2940
2941 static void
redraw_scrollbar(FL_OBJECT * obj)2942 redraw_scrollbar( FL_OBJECT * obj )
2943 {
2944 FLI_INPUT_SPEC *sp = obj->spec;
2945
2946 fl_freeze_form( obj->form );
2947
2948 if ( sp->v_on )
2949 {
2950 fl_set_scrollbar_size( sp->vscroll, sp->vsize );
2951 fl_set_scrollbar_value( sp->vscroll, sp->vval );
2952 if ( sp->vsize != 1.0 )
2953 fl_set_scrollbar_increment( sp->vscroll, sp->vinc1, sp->vinc2 );
2954 fl_redraw_object( sp->vscroll );
2955 }
2956
2957 if ( sp->h_on )
2958 {
2959 fl_set_scrollbar_size( sp->hscroll, sp->hsize );
2960 fl_set_scrollbar_value( sp->hscroll, sp->hval );
2961 if ( sp->hsize != 1.0 )
2962 fl_set_scrollbar_increment( sp->hscroll, sp->hinc1, sp->hinc2 );
2963 fl_redraw_object( sp->hscroll );
2964 }
2965
2966 if ( sp->attrib )
2967 {
2968 fl_redraw_object( sp->input );
2969 sp->attrib = 0;
2970 }
2971
2972 if ( sp->dead_area && FL_ObjWin( obj ) )
2973 {
2974 sp->dead_area = 0;
2975 fl_winset( FL_ObjWin( obj ) );
2976 fl_draw_box( FL_FLAT_BOX, sp->dummy->x + sp->dummy->w - sp->vw,
2977 sp->dummy->y + sp->dummy->h - sp->hh, sp->vw,
2978 sp->hh, sp->hscroll->col1, 1 );
2979 }
2980
2981 fl_unfreeze_form( obj->form );
2982 }
2983
2984
2985 /***************************************
2986 ***************************************/
2987
2988 void
fl_set_input_cursor_visible(FL_OBJECT * obj,int visible)2989 fl_set_input_cursor_visible( FL_OBJECT * obj,
2990 int visible )
2991 {
2992 FLI_INPUT_SPEC *sp = obj->spec;
2993
2994 if ( sp->cursor_visible != visible )
2995 {
2996 sp->cursor_visible = visible;
2997 fl_redraw_object( obj );
2998 }
2999 }
3000
3001
3002 /***************************************
3003 ***************************************/
3004
3005 int
fl_input_changed(FL_OBJECT * obj)3006 fl_input_changed( FL_OBJECT * obj )
3007 {
3008 return ( ( FLI_INPUT_SPEC * ) obj->spec )->changed;
3009 }
3010
3011
3012 /***************************************
3013 ***************************************/
3014
3015 int
fl_set_input_mode(int mode)3016 fl_set_input_mode( int mode )
3017 {
3018 int old_mode = Input_Mode;
3019
3020 Input_Mode = mode == FL_DOS_INPUT_MODE ?
3021 FL_DOS_INPUT_MODE : FL_NORMAL_INPUT_MODE;
3022
3023 return old_mode;
3024 }
3025
3026
3027 /*
3028 * Local variables:
3029 * tab-width: 4
3030 * indent-tabs-mode: nil
3031 * End:
3032 */
3033